mirror of https://github.com/SixLabors/ImageSharp
Browse Source
Former-commit-id: 42f38934bd4650dfdb7e733bebcdbe11eb57cd1f Former-commit-id: ff53006f57bd6b40ee863692b41eda42ce33b7b3 Former-commit-id: d1358cebb22a24144a19eef570c23e645a42714aaf/merge-core
8 changed files with 630 additions and 88 deletions
@ -0,0 +1,397 @@ |
|||
// <copyright file="Rational.cs" company="James Jackson-South">
|
|||
// Copyright (c) James Jackson-South and contributors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
// </copyright>
|
|||
|
|||
namespace ImageProcessorCore |
|||
{ |
|||
using System; |
|||
using System.Globalization; |
|||
using System.Numerics; |
|||
using System.Runtime.InteropServices; |
|||
using System.Text; |
|||
|
|||
/// <summary>
|
|||
/// Represents a number that can be expressed as a fraction
|
|||
/// </summary>
|
|||
/// <remarks>
|
|||
/// This is a very simplified implimentation of a rational number designed for use with
|
|||
/// metadata only.
|
|||
/// </remarks>
|
|||
public struct Rational : IEquatable<Rational> |
|||
{ |
|||
/// <summary>
|
|||
/// Represents a rational object that is not a number.
|
|||
/// </summary>
|
|||
public static Rational Indeterminate = new Rational(0, 0); |
|||
|
|||
/// <summary>
|
|||
/// Represents a rational object that is equal to 0.
|
|||
/// </summary>
|
|||
public static Rational Zero = new Rational(0, 1); |
|||
|
|||
/// <summary>
|
|||
/// Represents a rational object that is equal to 1.
|
|||
/// </summary>
|
|||
public static Rational One = new Rational(1, 1); |
|||
|
|||
/// <summary>
|
|||
/// Represents a Rational object that is equal to negative infinity (-1, 0).
|
|||
/// </summary>
|
|||
public static readonly Rational NegativeInfinity = new Rational(-1, 0); |
|||
|
|||
/// <summary>
|
|||
/// Represents a Rational object that is equal to positive infinity (+1, 0).
|
|||
/// </summary>
|
|||
public static readonly Rational PositiveInfinity = new Rational(1, 0); |
|||
|
|||
/// <summary>
|
|||
/// Initializes a new instance of the <see cref="Rational"/> struct.
|
|||
/// </summary>
|
|||
/// <param name="numerator">
|
|||
/// The number above the line in a vulgar fraction showing how many of the parts
|
|||
/// indicated by the denominator are taken.
|
|||
/// </param>
|
|||
/// <param name="denominator">
|
|||
/// The number below the line in a vulgar fraction; a divisor.
|
|||
/// </param>
|
|||
public Rational(uint numerator, uint denominator) |
|||
: this() |
|||
{ |
|||
this.Numerator = numerator; |
|||
this.Denominator = denominator; |
|||
|
|||
this.Simplify(); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Initializes a new instance of the <see cref="Rational"/> struct.
|
|||
/// </summary>
|
|||
/// <param name="numerator">
|
|||
/// The number above the line in a vulgar fraction showing how many of the parts
|
|||
/// indicated by the denominator are taken.
|
|||
/// </param>
|
|||
/// <param name="denominator">
|
|||
/// The number below the line in a vulgar fraction; a divisor.
|
|||
/// </param>
|
|||
public Rational(int numerator, int denominator) |
|||
: this() |
|||
{ |
|||
this.Numerator = numerator; |
|||
this.Denominator = denominator; |
|||
|
|||
this.Simplify(); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Initializes a new instance of the <see cref="Rational"/> struct.
|
|||
/// </summary>
|
|||
/// <param name="numerator">
|
|||
/// The number above the line in a vulgar fraction showing how many of the parts
|
|||
/// indicated by the denominator are taken.
|
|||
/// </param>
|
|||
/// <param name="denominator">
|
|||
/// The number below the line in a vulgar fraction; a divisor.
|
|||
/// </param>
|
|||
public Rational(BigInteger numerator, BigInteger denominator) |
|||
: this() |
|||
{ |
|||
this.Numerator = numerator; |
|||
this.Denominator = denominator; |
|||
|
|||
this.Simplify(); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Initializes a new instance of the <see cref="Rational"/> struct.
|
|||
/// </summary>
|
|||
/// <param name="value">The big integer to create the rational from.</param>
|
|||
public Rational(BigInteger value) |
|||
: this() |
|||
{ |
|||
this.Numerator = value; |
|||
this.Denominator = BigInteger.One; |
|||
|
|||
this.Simplify(); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Initializes a new instance of the <see cref="Rational"/> struct.
|
|||
/// </summary>
|
|||
/// <param name="value">The double to create the rational from.</param>
|
|||
public Rational(double value) |
|||
: this() |
|||
{ |
|||
if (double.IsNaN(value)) |
|||
{ |
|||
this = Indeterminate; |
|||
return; |
|||
} |
|||
else if (double.IsPositiveInfinity(value)) |
|||
{ |
|||
this = PositiveInfinity; |
|||
return; |
|||
} |
|||
else if (double.IsNegativeInfinity(value)) |
|||
{ |
|||
this = NegativeInfinity; |
|||
return; |
|||
} |
|||
|
|||
this = Parse(value.ToString("R", CultureInfo.InvariantCulture)); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Gets the numerator of a number.
|
|||
/// </summary>
|
|||
public BigInteger Numerator { get; private set; } |
|||
|
|||
/// <summary>
|
|||
/// Gets the denominator of a number.
|
|||
/// </summary>
|
|||
public BigInteger Denominator { get; private set; } |
|||
|
|||
/// <summary>
|
|||
/// Gets a value indicating whether this instance is indeterminate.
|
|||
/// </summary>
|
|||
public bool IsIndeterminate => (this.Equals(Indeterminate)); |
|||
|
|||
/// <summary>
|
|||
/// Gets a value indicating whether this instance is an integer.
|
|||
/// </summary>
|
|||
public bool IsInteger => (this.Denominator == 1); |
|||
|
|||
/// <summary>
|
|||
/// Gets a value indicating whether this instance is equal to 0
|
|||
/// </summary>
|
|||
public bool IsZero => (this.Equals(Zero)); |
|||
|
|||
/// <summary>
|
|||
/// Gets a value indicating whether this instance is equal to 1.
|
|||
/// </summary>
|
|||
public bool IsOne => (this.Equals(One)); |
|||
|
|||
/// <summary>
|
|||
/// Gets a value indicating whether this instance is equal to negative infinity (-1, 0).
|
|||
/// </summary>
|
|||
public bool IsNegativeInfinity => (this.Equals(NegativeInfinity)); |
|||
|
|||
/// <summary>
|
|||
/// Gets a value indicating whether this instance is equal to positive infinity (1, 0).
|
|||
/// </summary>
|
|||
public bool IsPositiveInfinity => (this.Equals(PositiveInfinity)); |
|||
|
|||
/// <summary>
|
|||
/// Converts a rational number to the nearest double.
|
|||
/// </summary>
|
|||
/// <returns>
|
|||
/// The <see cref="double"/>.
|
|||
/// </returns>
|
|||
public double ToDouble() |
|||
{ |
|||
if (this.IsIndeterminate) |
|||
{ |
|||
return double.NaN; |
|||
} |
|||
|
|||
if (this.IsPositiveInfinity) |
|||
{ |
|||
return double.PositiveInfinity; |
|||
} |
|||
|
|||
if (this.IsNegativeInfinity) |
|||
{ |
|||
return double.NegativeInfinity; |
|||
} |
|||
|
|||
if (this.IsInteger) |
|||
{ |
|||
return (double)this.Numerator; |
|||
} |
|||
|
|||
return (double)(this.Numerator / this.Denominator); |
|||
} |
|||
|
|||
/// <inheritdoc/>
|
|||
public override bool Equals(object obj) |
|||
{ |
|||
if (obj is Rational) |
|||
{ |
|||
return this.Equals((Rational)obj); |
|||
} |
|||
|
|||
return false; |
|||
} |
|||
|
|||
/// <inheritdoc/>
|
|||
public bool Equals(Rational other) |
|||
{ |
|||
if (this.Denominator == other.Denominator) |
|||
{ |
|||
return this.Numerator == other.Numerator; |
|||
} |
|||
else if (this.Numerator == BigInteger.Zero && this.Denominator == BigInteger.Zero) |
|||
{ |
|||
return other.Numerator == BigInteger.Zero && other.Denominator == BigInteger.Zero; |
|||
} |
|||
else if (other.Numerator == BigInteger.Zero && other.Denominator == BigInteger.Zero) |
|||
{ |
|||
return this.Numerator == BigInteger.Zero && this.Denominator == BigInteger.Zero; |
|||
} |
|||
else |
|||
{ |
|||
return (this.Numerator * other.Denominator) == (this.Denominator * other.Numerator); |
|||
} |
|||
} |
|||
|
|||
/// <inheritdoc/>
|
|||
public override int GetHashCode() |
|||
{ |
|||
unchecked |
|||
{ |
|||
return ((int)this.Numerator * 397) ^ (int)this.Denominator; |
|||
} |
|||
} |
|||
|
|||
/// <inheritdoc/>
|
|||
public override string ToString() |
|||
{ |
|||
return this.ToString(CultureInfo.InvariantCulture); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Converts the numeric value of this instance to its equivalent string representation using
|
|||
/// the specified culture-specific format information.
|
|||
/// </summary>
|
|||
/// <param name="provider">
|
|||
/// An object that supplies culture-specific formatting information.
|
|||
/// </param>
|
|||
/// <returns></returns>
|
|||
public string ToString(IFormatProvider provider) |
|||
|
|||
{ |
|||
if (this.IsIndeterminate) |
|||
{ |
|||
return "[ Indeterminate ]"; |
|||
} |
|||
|
|||
if (this.IsPositiveInfinity) |
|||
{ |
|||
return "[ PositiveInfinity ]"; |
|||
} |
|||
|
|||
if (this.IsNegativeInfinity) |
|||
{ |
|||
return "[ NegativeInfinity ]"; |
|||
} |
|||
|
|||
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(); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Simplifies the rational.
|
|||
/// </summary>
|
|||
private void Simplify() |
|||
{ |
|||
if (this.IsIndeterminate) |
|||
{ |
|||
return; |
|||
} |
|||
|
|||
if (this.IsNegativeInfinity) |
|||
{ |
|||
return; |
|||
} |
|||
|
|||
if (this.IsPositiveInfinity) |
|||
{ |
|||
return; |
|||
} |
|||
|
|||
if (this.IsInteger) |
|||
{ |
|||
return; |
|||
} |
|||
|
|||
if (this.Numerator == BigInteger.Zero) |
|||
{ |
|||
Denominator = BigInteger.One; |
|||
return; |
|||
} |
|||
|
|||
if (this.Numerator == this.Denominator) |
|||
{ |
|||
this.Numerator = BigInteger.One; |
|||
this.Denominator = BigInteger.One; |
|||
return; |
|||
} |
|||
|
|||
BigInteger gcd = BigInteger.GreatestCommonDivisor(this.Numerator, this.Denominator); |
|||
if (gcd > BigInteger.One) |
|||
{ |
|||
this.Numerator = this.Numerator / gcd; |
|||
this.Denominator = this.Denominator / gcd; |
|||
} |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Converts the string representation of a number into its rational value
|
|||
/// </summary>
|
|||
/// <param name="value">A string that contains a number to convert.</param>
|
|||
/// <returns>The <see cref="Rational"/></returns>
|
|||
internal static Rational Parse(string value) |
|||
{ |
|||
int periodIndex = value.IndexOf("."); |
|||
int eIndeix = value.IndexOf("E"); |
|||
int slashIndex = value.IndexOf("/"); |
|||
|
|||
// An integer such as 7
|
|||
if (periodIndex == -1 && eIndeix == -1 && slashIndex == -1) |
|||
{ |
|||
return new Rational(BigInteger.Parse(value)); |
|||
} |
|||
|
|||
// A fraction such as 3/7
|
|||
if (periodIndex == -1 && eIndeix == -1 && slashIndex != -1) |
|||
{ |
|||
return new Rational(BigInteger.Parse(value.Substring(0, slashIndex)), |
|||
BigInteger.Parse(value.Substring(slashIndex + 1))); |
|||
} |
|||
|
|||
// No scientific Notation such as 5.997
|
|||
if (eIndeix == -1) |
|||
{ |
|||
BigInteger n = BigInteger.Parse(value.Replace(".", "")); |
|||
BigInteger d = (BigInteger)Math.Pow(10, value.Length - periodIndex - 1); |
|||
return new Rational(n, d); |
|||
} |
|||
|
|||
// Scientific notation such as 2.4556E-2
|
|||
int characteristic = int.Parse(value.Substring(eIndeix + 1)); |
|||
BigInteger ten = 10; |
|||
BigInteger numerator = BigInteger.Parse(value.Substring(0, eIndeix).Replace(".", "")); |
|||
BigInteger denominator = new BigInteger(Math.Pow(10, eIndeix - periodIndex - 1)); |
|||
BigInteger charPower = BigInteger.Pow(ten, Math.Abs(characteristic)); |
|||
|
|||
if (characteristic > 0) |
|||
{ |
|||
numerator = numerator * charPower; |
|||
} |
|||
else |
|||
{ |
|||
denominator = denominator * charPower; |
|||
} |
|||
|
|||
return new Rational(numerator, denominator); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,3 @@ |
|||
version https://git-lfs.github.com/spec/v1 |
|||
oid sha256:8a9d04b92d0de5836c59ede8ae421235488e4031e893e07b1fe7e4b78f6a9901 |
|||
size 32764 |
|||
Loading…
Reference in new issue