diff --git a/src/ImageProcessorCore/Numerics/BigRational.cs b/src/ImageProcessorCore/Numerics/BigRational.cs deleted file mode 100644 index 749be87f8..000000000 --- a/src/ImageProcessorCore/Numerics/BigRational.cs +++ /dev/null @@ -1,219 +0,0 @@ -// -// Copyright (c) James Jackson-South and contributors. -// Licensed under the Apache License, Version 2.0. -// - -namespace ImageProcessorCore -{ - using System; - using System.Text; - - internal struct BigRational : IEquatable - { - private bool IsIndeterminate - { - get - { - if (Denominator != 0) - return false; - - return Numerator == 0; - } - } - - private bool IsInteger => Denominator == 1; - - private bool IsNegativeInfinity - { - get - { - if (Denominator != 0) - return false; - - return Numerator == -1; - } - } - - private bool IsPositiveInfinity - { - get - { - if (Denominator != 0) - return false; - - return Numerator == 1; - } - } - - private bool IsZero - { - get - { - if (Denominator != 1) - return false; - - return Numerator == 0; - } - } - - private static long GreatestCommonDivisor(long a, long b) - { - return b == 0 ? a : GreatestCommonDivisor(b, a % b); - } - - private void Simplify() - { - if (IsIndeterminate) - return; - - if (IsNegativeInfinity) - return; - - if (IsPositiveInfinity) - return; - - if (IsInteger) - return; - - if (IsZero) - return; - - if (Numerator == 0) - { - Denominator = 0; - return; - } - - if (Numerator == Denominator) - { - Numerator = 1; - Denominator = 1; - } - - long gcd = GreatestCommonDivisor(Math.Abs(Numerator), Math.Abs(Denominator)); - if (gcd > 1) - { - Numerator = Numerator / gcd; - Denominator = Denominator / gcd; - } - } - - public BigRational(long numerator, long denominator) - : this(numerator, denominator, false) - { - } - - public BigRational(long numerator, long denominator, bool simplify) - { - Numerator = numerator; - Denominator = denominator; - - if (simplify) - Simplify(); - } - - public BigRational(double value, bool bestPrecision) - { - if (double.IsNaN(value)) - { - Numerator = Denominator = 0; - return; - } - - if (double.IsPositiveInfinity(value)) - { - Numerator = 1; - Denominator = 0; - return; - } - - if (double.IsNegativeInfinity(value)) - { - Numerator = -1; - Denominator = 0; - return; - } - - Numerator = 1; - Denominator = 1; - - double val = Math.Abs(value); - double df = Numerator / (double)Denominator; - double epsilon = bestPrecision ? double.Epsilon : .000001; - - while (Math.Abs(df - val) > epsilon) - { - if (df < val) - Numerator++; - else - { - Denominator++; - Numerator = (int)(val * Denominator); - } - - df = Numerator / (double)Denominator; - } - - if (value < 0.0) - Numerator *= -1; - - Simplify(); - } - - public long Denominator - { - get; - private set; - } - - public long Numerator - { - get; - private set; - } - - public bool Equals(BigRational other) - { - if (Denominator == other.Denominator) - return Numerator == other.Numerator; - - if (Numerator == 0 && Denominator == 0) - return other.Numerator == 0 && other.Denominator == 0; - - if (other.Numerator == 0 && other.Denominator == 0) - return Numerator == 0 && Denominator == 0; - - return (Numerator * other.Denominator) == (Denominator * other.Numerator); - } - - public override int GetHashCode() - { - return ((Numerator * 397) ^ Denominator).GetHashCode(); - } - - public string ToString(IFormatProvider provider) - { - if (IsIndeterminate) - return "[ Indeterminate ]"; - - if (IsPositiveInfinity) - return "[ PositiveInfinity ]"; - - if (IsNegativeInfinity) - return "[ NegativeInfinity ]"; - - if (IsZero) - return "0"; - - if (IsInteger) - return Numerator.ToString(provider); - - StringBuilder sb = new StringBuilder(); - sb.Append(Numerator.ToString(provider)); - sb.Append("/"); - sb.Append(Denominator.ToString(provider)); - - return sb.ToString(); - } - } -} \ No newline at end of file diff --git a/src/ImageProcessorCore/Numerics/LongRational.cs b/src/ImageProcessorCore/Numerics/LongRational.cs new file mode 100644 index 000000000..a348b9001 --- /dev/null +++ b/src/ImageProcessorCore/Numerics/LongRational.cs @@ -0,0 +1,355 @@ +// +// Copyright (c) James Jackson-South and contributors. +// Licensed under the Apache License, Version 2.0. +// + +namespace ImageProcessorCore +{ + using System; + using System.Globalization; + using System.Text; + + /// + /// Represents a number that can be expressed as a fraction + /// + /// + /// This is a very simplified implementation of a rational number designed for use with metadata only. + /// + internal struct LongRational : IEquatable + { + /// + /// 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. + /// + 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; + } + + /// + /// Gets the denominator of a number. + /// + public long Denominator + { + get; + private set; + } + + /// + /// Gets a value indicating whether this instance is indeterminate. + /// + public bool IsIndeterminate + { + get + { + if (this.Denominator != 0) + { + return false; + } + + return this.Numerator == 0; + } + } + + /// + /// Gets a value indicating whether this instance is an integer (n, 1) + /// + public bool IsInteger => this.Denominator == 1; + + /// + /// 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; + } + } + + /// + /// 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; + } + } + + /// + /// 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 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); + } + + /// + public override int GetHashCode() + { + return this.GetHashCode(this); + } + + /// + public override string ToString() + { + return this.ToString(CultureInfo.InvariantCulture); + } + + /// + /// Converts the numeric value of this instance to its equivalent string representation using + /// the specified culture-specific format information. + /// + /// + /// An object that supplies culture-specific formatting information. + /// + /// The + public string ToString(IFormatProvider provider) + { + if (this.IsIndeterminate) + { + return "[ Indeterminate ]"; + } + + if (this.IsPositiveInfinity) + { + return "[ PositiveInfinity ]"; + } + + if (this.IsNegativeInfinity) + { + return "[ NegativeInfinity ]"; + } + + if (this.IsZero) + { + return "0"; + } + + if (this.IsInteger) + { + return this.Numerator.ToString(provider); + } + + StringBuilder sb = new StringBuilder(); + sb.Append(this.Numerator.ToString("R", provider)); + sb.Append("/"); + sb.Append(this.Denominator.ToString("R", provider)); + return sb.ToString(); + } + + /// + /// 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 + /// + private void Simplify() + { + if (this.IsIndeterminate) + { + return; + } + + if (this.IsNegativeInfinity) + { + return; + } + + if (this.IsPositiveInfinity) + { + return; + } + + if (this.IsInteger) + { + return; + } + + if (this.IsZero) + { + return; + } + + if (this.Numerator == 0) + { + this.Denominator = 0; + return; + } + + if (this.Numerator == this.Denominator) + { + this.Numerator = 1; + this.Denominator = 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; + } + } + + /// + /// 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(); + } + } +} \ No newline at end of file diff --git a/src/ImageProcessorCore/Numerics/Rational.cs b/src/ImageProcessorCore/Numerics/Rational.cs index 1de71fa86..dc05f8e2e 100644 --- a/src/ImageProcessorCore/Numerics/Rational.cs +++ b/src/ImageProcessorCore/Numerics/Rational.cs @@ -12,74 +12,84 @@ namespace ImageProcessorCore /// Represents a number that can be expressed as a fraction. /// /// - /// This is a very simplified implimentation of a rational number designed for use with metadata only. + /// This is a very simplified implementation of a rational number designed for use with metadata only. /// public struct Rational : IEquatable { /// /// Initializes a new instance of the struct. /// - ///The to convert to an instance of this type. - public Rational(double value) - : this(value, false) + /// The to create the rational from. + public Rational(uint value) + : this(value, 1) { } /// /// Initializes a new instance of the struct. /// - ///The to convert to an instance of this type. - ///Specifies if the instance should be created with the best precision possible. - public Rational(double value, bool bestPrecision) + /// 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. + public Rational(uint numerator, uint denominator) + : this(numerator, denominator, true) { - BigRational rational = new BigRational(Math.Abs(value), bestPrecision); - - Numerator = (uint)rational.Numerator; - Denominator = (uint)rational.Denominator; } /// /// Initializes a new instance of the struct. /// - /// The integer to create the rational from. - public Rational(uint value) - : this(value, 1) + /// 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. + /// Specified if the rational should be simplified. + public Rational(uint numerator, uint denominator, bool simplify) { + LongRational rational = new LongRational(numerator, denominator, simplify); + + this.Numerator = (uint)rational.Numerator; + this.Denominator = (uint)rational.Denominator; } /// /// 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. - public Rational(uint numerator, uint denominator) - : this(numerator, denominator, true) + /// The to create the instance from. + public Rational(double value) + : this(value, 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. - /// Specified if the rational should be simplified. - public Rational(uint numerator, uint denominator, bool simplify) + /// The to create the instance from. + /// Whether to use the best possible precision when parsing the value. + public Rational(double value, bool bestPrecision) { - BigRational rational = new BigRational(numerator, denominator, simplify); + LongRational rational = new LongRational(Math.Abs(value), bestPrecision); - Numerator = (uint)rational.Numerator; - Denominator = (uint)rational.Denominator; + this.Numerator = (uint)rational.Numerator; + this.Denominator = (uint)rational.Denominator; } + /// + /// Gets the numerator of a number. + /// + public uint Numerator { get; } + + /// + /// Gets the denominator of a number. + /// + public uint Denominator { get; } + /// /// Determines whether the specified instances are considered equal. /// /// The first to compare. /// The second to compare. - /// + /// The public static bool operator ==(Rational left, Rational right) { - return Equals(left, right); + return Rational.Equals(left, right); } /// @@ -87,79 +97,61 @@ namespace ImageProcessorCore /// /// The first to compare. /// The second to compare. - /// + /// The public static bool operator !=(Rational left, Rational right) { - return !Equals(left, right); + return !Rational.Equals(left, right); } /// - /// Gets the numerator of a number. + /// Converts the specified to an instance of this type. /// - public uint Numerator + /// The to convert to an instance of this type. + /// + /// The . + /// + public static Rational FromDouble(double value) { - get; - private set; + return new Rational(value, false); } /// - /// Gets the denominator of a number. + /// Converts the specified to an instance of this type. /// - public uint Denominator + /// The to convert to an instance of this type. + /// Whether to use the best possible precision when parsing the value. + /// + /// The . + /// + public static Rational FromDouble(double value, bool bestPrecision) { - get; - private set; + return new Rational(value, bestPrecision); } - /// - /// Determines whether the specified is equal to this . - /// - ///The to compare this with. + /// public override bool Equals(object obj) { if (obj is Rational) - return Equals((Rational)obj); + { + return this.Equals((Rational)obj); + } return false; } - /// - /// Determines whether the specified is equal to this . - /// - ///The to compare this with. + /// public bool Equals(Rational other) { - BigRational left = new BigRational(Numerator, Denominator); - BigRational right = new BigRational(other.Numerator, other.Denominator); + LongRational left = new LongRational(this.Numerator, this.Denominator); + LongRational right = new LongRational(other.Numerator, other.Denominator); return left.Equals(right); } - /// - /// Converts the specified to an instance of this type. - /// - ///The to convert to an instance of this type. - public static Rational FromDouble(double value) - { - return new Rational(value, false); - } - - /// - /// Converts the specified to an instance of this type. - /// - ///The to convert to an instance of this type. - ///Specifies if the instance should be created with the best precision possible. - public static Rational FromDouble(double value, bool bestPrecision) - { - return new Rational(value, bestPrecision); - } - - /// - /// Serves as a hash of this type. - /// + /// public override int GetHashCode() { - BigRational self = new BigRational(Numerator, Denominator); + LongRational self = new LongRational(this.Numerator, this.Denominator); return self.GetHashCode(); } @@ -171,28 +163,26 @@ namespace ImageProcessorCore /// public double ToDouble() { - return Numerator / (double)Denominator; + return this.Numerator / (double)this.Denominator; } - /// - /// Converts the numeric value of this instance to its equivalent string representation. - /// + /// public override string ToString() { - return ToString(CultureInfo.InvariantCulture); + return this.ToString(CultureInfo.InvariantCulture); } /// - /// Converts the numeric value of this instance to its equivalent string representation using + /// Converts the numeric value of this instance to its equivalent string representation using /// the specified culture-specific format information. /// /// /// An object that supplies culture-specific formatting information. /// - /// + /// The public string ToString(IFormatProvider provider) { - BigRational rational = new BigRational(Numerator, Denominator); + LongRational rational = new LongRational(this.Numerator, this.Denominator); return rational.ToString(provider); } } diff --git a/src/ImageProcessorCore/Numerics/SignedRational.cs b/src/ImageProcessorCore/Numerics/SignedRational.cs index d216b30d4..b2bb9ab34 100644 --- a/src/ImageProcessorCore/Numerics/SignedRational.cs +++ b/src/ImageProcessorCore/Numerics/SignedRational.cs @@ -1,4 +1,4 @@ -// +// // Copyright (c) James Jackson-South and contributors. // Licensed under the Apache License, Version 2.0. // @@ -12,74 +12,84 @@ namespace ImageProcessorCore /// Represents a number that can be expressed as a fraction. /// /// - /// This is a very simplified implimentation of a rational number designed for use with metadata only. + /// This is a very simplified implementation of a rational number designed for use with metadata only. /// public struct SignedRational : IEquatable { /// /// Initializes a new instance of the struct. /// - ///The to convert to an instance of this type. - public SignedRational(double value) - : this(value, false) + /// The to create the rational from. + public SignedRational(int value) + : this(value, 1) { } /// /// Initializes a new instance of the struct. /// - ///The to convert to an instance of this type. - ///Specifies if the instance should be created with the best precision possible. - public SignedRational(double value, bool bestPrecision) + /// 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. + public SignedRational(int numerator, int denominator) + : this(numerator, denominator, true) { - BigRational rational = new BigRational(value, bestPrecision); - - Numerator = (int)rational.Numerator; - Denominator = (int)rational.Denominator; } /// /// Initializes a new instance of the struct. /// - /// The integer to create the rational from. - public SignedRational(int value) - : this(value, 1) + /// 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. + /// Specified if the rational should be simplified. + public SignedRational(int numerator, int denominator, bool simplify) { + LongRational rational = new LongRational(numerator, denominator, simplify); + + this.Numerator = (int)rational.Numerator; + this.Denominator = (int)rational.Denominator; } /// /// 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. - public SignedRational(int numerator, int denominator) - : this(numerator, denominator, true) + /// The to create the instance from. + public SignedRational(double value) + : this(value, 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. - /// Specified if the rational should be simplified. - public SignedRational(int numerator, int denominator, bool simplify) + /// The to create the instance from. + /// Whether to use the best possible precision when parsing the value. + public SignedRational(double value, bool bestPrecision) { - BigRational rational = new BigRational(numerator, denominator, simplify); + LongRational rational = new LongRational(value, bestPrecision); - Numerator = (int)rational.Numerator; - Denominator = (int)rational.Denominator; + this.Numerator = (int)rational.Numerator; + this.Denominator = (int)rational.Denominator; } + /// + /// Gets the numerator of a number. + /// + public int Numerator { get; } + + /// + /// Gets the denominator of a number. + /// + public int Denominator { get; } + /// /// Determines whether the specified instances are considered equal. /// /// The first to compare. /// The second to compare. - /// + /// The public static bool operator ==(SignedRational left, SignedRational right) { - return Equals(left, right); + return SignedRational.Equals(left, right); } /// @@ -87,79 +97,61 @@ namespace ImageProcessorCore /// /// The first to compare. /// The second to compare. - /// + /// The public static bool operator !=(SignedRational left, SignedRational right) { - return !Equals(left, right); + return !SignedRational.Equals(left, right); } /// - /// Gets the numerator of a number. + /// Converts the specified to an instance of this type. /// - public int Numerator + /// The to convert to an instance of this type. + /// + /// The . + /// + public static SignedRational FromDouble(double value) { - get; - private set; + return new SignedRational(value, false); } /// - /// Gets the denominator of a number. + /// Converts the specified to an instance of this type. /// - public int Denominator + /// The to convert to an instance of this type. + /// Whether to use the best possible precision when parsing the value. + /// + /// The . + /// + public static SignedRational FromDouble(double value, bool bestPrecision) { - get; - private set; + return new SignedRational(value, bestPrecision); } - /// - /// Determines whether the specified is equal to this . - /// - ///The to compare this with. + /// public override bool Equals(object obj) { if (obj is SignedRational) - return Equals((SignedRational)obj); + { + return this.Equals((SignedRational)obj); + } return false; } - /// - /// Determines whether the specified is equal to this . - /// - ///The to compare this with. + /// public bool Equals(SignedRational other) { - BigRational left = new BigRational(Numerator, Denominator); - BigRational right = new BigRational(other.Numerator, other.Denominator); + LongRational left = new LongRational(this.Numerator, this.Denominator); + LongRational right = new LongRational(other.Numerator, other.Denominator); return left.Equals(right); } - /// - /// Converts the specified to an instance of this type. - /// - ///The to convert to an instance of this type. - public static SignedRational FromDouble(double value) - { - return new SignedRational(value, false); - } - - /// - /// Converts the specified to an instance of this type. - /// - ///The to convert to an instance of this type. - ///Specifies if the instance should be created with the best precision possible. - public static SignedRational FromDouble(double value, bool bestPrecision) - { - return new SignedRational(value, bestPrecision); - } - - /// - /// Serves as a hash of this type. - /// + /// public override int GetHashCode() { - BigRational self = new BigRational(Numerator, Denominator); + LongRational self = new LongRational(this.Numerator, this.Denominator); return self.GetHashCode(); } @@ -171,28 +163,26 @@ namespace ImageProcessorCore /// public double ToDouble() { - return Numerator / (double)Denominator; + return this.Numerator / (double)this.Denominator; } - /// - /// Converts the numeric value of this instance to its equivalent string representation. - /// + /// public override string ToString() { - return ToString(CultureInfo.InvariantCulture); + return this.ToString(CultureInfo.InvariantCulture); } /// - /// Converts the numeric value of this instance to its equivalent string representation using + /// Converts the numeric value of this instance to its equivalent string representation using /// the specified culture-specific format information. /// /// /// An object that supplies culture-specific formatting information. /// - /// + /// The public string ToString(IFormatProvider provider) { - BigRational rational = new BigRational(Numerator, Denominator); + LongRational rational = new LongRational(this.Numerator, this.Denominator); return rational.ToString(provider); } }