diff --git a/src/ImageSharp/Primitives/LongRational.cs b/src/ImageSharp/Primitives/LongRational.cs index 9addf1e18a..d790b110d0 100644 --- a/src/ImageSharp/Primitives/LongRational.cs +++ b/src/ImageSharp/Primitives/LongRational.cs @@ -13,7 +13,7 @@ namespace SixLabors.ImageSharp.Primitives /// /// This is a very simplified implementation of a rational number designed for use with metadata only. /// - internal struct LongRational : IEquatable + internal readonly struct LongRational : IEquatable { /// /// Initializes a new instance of the struct. @@ -26,126 +26,25 @@ namespace SixLabors.ImageSharp.Primitives /// The number below the line in a vulgar fraction; a divisor. /// public LongRational(long numerator, long denominator) - : this(numerator, denominator, false) - { - } - - /// - /// Initializes a new instance of the struct. - /// - /// - /// The number above the line in a vulgar fraction showing how many of the parts - /// indicated by the denominator are taken. - /// - /// - /// The number below the line in a vulgar fraction; a divisor. - /// - /// - /// Whether to attempt to simplify the fractional parts. - /// - public LongRational(long numerator, long denominator, bool simplify) - : this() { this.Numerator = numerator; this.Denominator = denominator; - - if (simplify) - { - this.Simplify(); - } - } - - /// - /// Initializes a new instance of the struct. - /// - /// The to create the instance from. - /// Whether to use the best possible precision when parsing the value. - public LongRational(double value, bool bestPrecision) - : this() - { - if (double.IsNaN(value)) - { - this.Numerator = this.Denominator = 0; - return; - } - - if (double.IsPositiveInfinity(value)) - { - this.Numerator = 1; - this.Denominator = 0; - return; - } - - if (double.IsNegativeInfinity(value)) - { - this.Numerator = -1; - this.Denominator = 0; - return; - } - - this.Numerator = 1; - this.Denominator = 1; - - double val = Math.Abs(value); - double df = this.Numerator / (double)this.Denominator; - double epsilon = bestPrecision ? double.Epsilon : .000001; - - while (Math.Abs(df - val) > epsilon) - { - if (df < val) - { - this.Numerator++; - } - else - { - this.Denominator++; - this.Numerator = (int)(val * this.Denominator); - } - - df = this.Numerator / (double)this.Denominator; - } - - if (value < 0.0) - { - this.Numerator *= -1; - } - - this.Simplify(); } /// /// Gets the numerator of a number. /// - public long Numerator - { - get; - private set; - } + public long Numerator { get; } /// /// Gets the denominator of a number. /// - public long Denominator - { - get; - private set; - } + public long Denominator { get; } /// /// Gets a value indicating whether this instance is indeterminate. /// - public bool IsIndeterminate - { - get - { - if (this.Denominator != 0) - { - return false; - } - - return this.Numerator == 0; - } - } + public bool IsIndeterminate => this.Denominator == 0 && this.Numerator == 0; /// /// Gets a value indicating whether this instance is an integer (n, 1) @@ -155,76 +54,28 @@ namespace SixLabors.ImageSharp.Primitives /// /// Gets a value indicating whether this instance is equal to negative infinity (-1, 0) /// - public bool IsNegativeInfinity - { - get - { - if (this.Denominator != 0) - { - return false; - } - - return this.Numerator == -1; - } - } + public bool IsNegativeInfinity => this.Denominator == 0 && this.Numerator == -1; /// /// Gets a value indicating whether this instance is equal to positive infinity (1, 0) /// - public bool IsPositiveInfinity - { - get - { - if (this.Denominator != 0) - { - return false; - } - - return this.Numerator == 1; - } - } + public bool IsPositiveInfinity => this.Denominator == 0 && this.Numerator == 1; /// /// Gets a value indicating whether this instance is equal to 0 (0, 1) /// - public bool IsZero - { - get - { - if (this.Denominator != 1) - { - return false; - } - - return this.Numerator == 0; - } - } + public bool IsZero => this.Denominator == 1 && this.Numerator == 0; /// public bool Equals(LongRational other) { - if (this.Denominator == other.Denominator) - { - return this.Numerator == other.Numerator; - } - - if (this.Numerator == 0 && this.Denominator == 0) - { - return other.Numerator == 0 && other.Denominator == 0; - } - - if (other.Numerator == 0 && other.Denominator == 0) - { - return this.Numerator == 0 && this.Denominator == 0; - } - - return (this.Numerator * other.Denominator) == (this.Denominator * other.Numerator); + return this.Numerator == other.Numerator && this.Denominator == other.Denominator; } /// public override int GetHashCode() { - return this.GetHashCode(this); + return ((this.Numerator * 397) ^ this.Denominator).GetHashCode(); } /// @@ -276,78 +127,100 @@ namespace SixLabors.ImageSharp.Primitives } /// - /// Finds the greatest common divisor of two values. + /// Create a new instance of the struct from a double value. /// - /// The first value - /// The second value - /// The - private static long GreatestCommonDivisor(long left, long right) + /// The to create the instance from. + /// Whether to use the best possible precision when parsing the value. + public static LongRational FromDouble(double value, bool bestPrecision) { - return right == 0 ? left : GreatestCommonDivisor(right, left % right); - } + if (double.IsNaN(value)) + { + return new LongRational(0, 0); + } - /// - /// Simplifies the - /// - private void Simplify() - { - if (this.IsIndeterminate) + if (double.IsPositiveInfinity(value)) { - return; + return new LongRational(1, 0); } - if (this.IsNegativeInfinity) + if (double.IsNegativeInfinity(value)) { - return; + return new LongRational(-1, 0); } - if (this.IsPositiveInfinity) + long numerator = 1; + long denominator = 1; + + double val = Math.Abs(value); + double df = numerator / (double)denominator; + double epsilon = bestPrecision ? double.Epsilon : .000001; + + while (Math.Abs(df - val) > epsilon) { - return; + if (df < val) + { + numerator++; + } + else + { + denominator++; + numerator = (int)(val * denominator); + } + + df = numerator / (double)denominator; } - if (this.IsInteger) + if (value < 0.0) { - return; + numerator *= -1; } - if (this.IsZero) + return new LongRational(numerator, denominator).Simplify(); + } + + /// + /// Finds the greatest common divisor of two values. + /// + /// The first value + /// The second value + /// The + private static long GreatestCommonDivisor(long left, long right) + { + return right == 0 ? left : GreatestCommonDivisor(right, left % right); + } + + /// + /// Simplifies the + /// + public LongRational Simplify() + { + if (this.IsIndeterminate || + this.IsNegativeInfinity || + this.IsPositiveInfinity || + this.IsInteger || + this.IsZero) { - return; + return this; } if (this.Numerator == 0) { - this.Denominator = 0; - return; + return new LongRational(0, 0); } if (this.Numerator == this.Denominator) { - this.Numerator = 1; - this.Denominator = 1; + return new LongRational(1, 1); } long gcd = GreatestCommonDivisor(Math.Abs(this.Numerator), Math.Abs(this.Denominator)); + if (gcd > 1) { - this.Numerator = this.Numerator / gcd; - this.Denominator = this.Denominator / gcd; + return new LongRational(this.Numerator / gcd, this.Denominator / gcd); } - } - /// - /// Returns the hash code for this instance. - /// - /// - /// The instance of to return the hash code for. - /// - /// - /// A 32-bit signed integer that is the hash code for this instance. - /// - private int GetHashCode(LongRational rational) - { - return ((rational.Numerator * 397) ^ rational.Denominator).GetHashCode(); + return this; } } } \ No newline at end of file diff --git a/src/ImageSharp/Primitives/Rational.cs b/src/ImageSharp/Primitives/Rational.cs index fa3961ffa8..b598f0e02f 100644 --- a/src/ImageSharp/Primitives/Rational.cs +++ b/src/ImageSharp/Primitives/Rational.cs @@ -41,10 +41,18 @@ namespace SixLabors.ImageSharp.Primitives /// Specified if the rational should be simplified. public Rational(uint numerator, uint denominator, bool simplify) { - var rational = new LongRational(numerator, denominator, simplify); - - this.Numerator = (uint)rational.Numerator; - this.Denominator = (uint)rational.Denominator; + if (simplify) + { + LongRational rational = new LongRational(numerator, denominator).Simplify(); + + this.Numerator = (uint)rational.Numerator; + this.Denominator = (uint)rational.Denominator; + } + else + { + this.Numerator = numerator; + this.Denominator = denominator; + } } /// @@ -63,7 +71,7 @@ namespace SixLabors.ImageSharp.Primitives /// Whether to use the best possible precision when parsing the value. public Rational(double value, bool bestPrecision) { - var rational = new LongRational(Math.Abs(value), bestPrecision); + var rational = LongRational.FromDouble(Math.Abs(value), bestPrecision); this.Numerator = (uint)rational.Numerator; this.Denominator = (uint)rational.Denominator; diff --git a/src/ImageSharp/Primitives/SignedRational.cs b/src/ImageSharp/Primitives/SignedRational.cs index bc0e41966e..7e486e4f22 100644 --- a/src/ImageSharp/Primitives/SignedRational.cs +++ b/src/ImageSharp/Primitives/SignedRational.cs @@ -41,10 +41,18 @@ namespace SixLabors.ImageSharp.Primitives /// Specified if the rational should be simplified. public SignedRational(int numerator, int denominator, bool simplify) { - var rational = new LongRational(numerator, denominator, simplify); - - this.Numerator = (int)rational.Numerator; - this.Denominator = (int)rational.Denominator; + if (simplify) + { + LongRational rational = new LongRational(numerator, denominator).Simplify(); + + this.Numerator = (int)rational.Numerator; + this.Denominator = (int)rational.Denominator; + } + else + { + this.Numerator = numerator; + this.Denominator = denominator; + } } /// @@ -63,7 +71,7 @@ namespace SixLabors.ImageSharp.Primitives /// Whether to use the best possible precision when parsing the value. public SignedRational(double value, bool bestPrecision) { - var rational = new LongRational(value, bestPrecision); + var rational = LongRational.FromDouble(value, bestPrecision); this.Numerator = (int)rational.Numerator; this.Denominator = (int)rational.Denominator;