Skip to content

Commit

Permalink
String formatting consolidated and inheritance of BigDecimal from IFo…
Browse files Browse the repository at this point in the history
…rmattable
  • Loading branch information
tsutomi committed Jul 10, 2024
1 parent d7cefaa commit 0a7681f
Show file tree
Hide file tree
Showing 3 changed files with 177 additions and 142 deletions.
182 changes: 55 additions & 127 deletions src/Deveel.Math/Math/BigDecimal_Convertible.cs
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ bool IConvertible.ToBoolean(IFormatProvider provider)

byte IConvertible.ToByte(IFormatProvider provider)
{
int value = ToInt32Exact();
var value = ToInt16Exact();
if (value > Byte.MaxValue || value < Byte.MinValue)
throw new InvalidCastException();

Expand All @@ -51,23 +51,23 @@ byte IConvertible.ToByte(IFormatProvider provider)

short IConvertible.ToInt16(IFormatProvider provider)
{
var value = ToInt16Exact();
var value = ToInt32Exact();
if (value > Int16.MaxValue || value < Int16.MinValue)
throw new InvalidCastException();

return value;
return (short) value;
}

ushort IConvertible.ToUInt16(IFormatProvider provider) => throw new NotSupportedException();

// TODO: use the IFormatProvider
int IConvertible.ToInt32(IFormatProvider provider)
{
var value = ToInt32Exact();
var value = ToInt64Exact();
if (value > Int32.MaxValue || value < Int32.MinValue)
throw new InvalidCastException();

return value;
return (int)value;
}

// TODO: verify if it is possible to convert to uint
Expand Down Expand Up @@ -112,7 +112,7 @@ decimal IConvertible.ToDecimal(IFormatProvider provider)

string IConvertible.ToString(IFormatProvider provider)
{
return ToString(provider);
return ToString(GeneralStringFormat, provider);
}

object IConvertible.ToType(Type conversionType, IFormatProvider provider)
Expand All @@ -134,106 +134,6 @@ public override string ToString()
return ToString(null);
}

/// <summary>
/// Converts this <see cref="BigDecimal"/> to a string representation
/// </summary>
/// <param name="provider"></param>
/// <returns></returns>
public string ToString(IFormatProvider provider)
{
if (provider == null)
provider = NumberFormatInfo.InvariantInfo;

return DecimalString.ToString(this, provider);
}

// TODO: use a IFormattable for the Engineering and the Plain string

/// <summary>
/// Returns a string representation of this number,
/// including all significant digits of this value
/// </summary>
/// <remarks>
/// <para>
/// If the scale is negative or if <c>scale - precision >= 6</c>
/// then engineering notation is used. Engineering notation is
/// similar to the scientific notation except that the exponent
/// is made to be a multiple of 3 such that the integer part
/// is lesser or equal to 1 and greater than 1000.
/// </para>
/// <para>
/// This overload uses the invariant culture to resolve the
/// format information for the string.
/// </para>
/// </remarks>
/// <returns>
/// Returns a string representation of this number in engineering
/// notation if necessary.
/// </returns>
public String ToEngineeringString()
{
return ToEngineeringString(null);
}

/// <summary>
/// Returns a string representation of this number,
/// including all significant digits of this value
/// </summary>
/// <param name="provider">The provider used to resolve the
/// format information to use.</param>
/// <remarks>
/// <para>
/// If the scale is negative or if <c>scale - precision >= 6</c>
/// then engineering notation is used. Engineering notation is
/// similar to the scientific notation except that the exponent
/// is made to be a multiple of 3 such that the integer part
/// is greater or equal than 1 and is smaller than 1000.
/// </para>
/// </remarks>
/// <returns>
/// Returns a string representation of this number in engineering
/// notation if necessary.
/// </returns>
public String ToEngineeringString(IFormatProvider provider)
{
if (provider == null)
provider = NumberFormatInfo.InvariantInfo;

return DecimalString.ToEngineeringString(this, provider);
}

/// <summary>
/// Returns a string representation of this <see cref="BigDecimal"/>
/// as a plain number, without any scientific notation.
/// </summary>
/// <param name="provider"></param>
/// <remarks>
/// <para>
/// This methods adds zeros where necessary.
/// </para>
/// <para>
/// If the string representation is used to create a new instance, this
/// instance is generally not identical to this instance as the precision
/// changes.
/// </para>
/// </remarks>
/// <returns>
/// Returns a string representation of this number without any
/// exponent part.
/// </returns>
public String ToPlainString(IFormatProvider provider)
{
if (provider == null)
provider = CultureInfo.InvariantCulture;

return DecimalString.ToPlainString(this, provider);
}

public String ToPlainString()
{
return ToPlainString(null);
}

/// <summary>
/// Converts this <see cref="BigDecimal"/> to a <see cref="BigInteger"/>
/// instance, discarding any fractional part.
Expand Down Expand Up @@ -400,6 +300,11 @@ public short ToInt16Exact()
return (short)ValueExact(16);
}

public byte ToByteExact()

Check warning on line 303 in src/Deveel.Math/Math/BigDecimal_Convertible.cs

View workflow job for this annotation

GitHub Actions / build (7.0.x, macos-latest) / build

Missing XML comment for publicly visible type or member 'BigDecimal.ToByteExact()'

Check warning on line 303 in src/Deveel.Math/Math/BigDecimal_Convertible.cs

View workflow job for this annotation

GitHub Actions / build (6.0.x, macos-latest) / build

Missing XML comment for publicly visible type or member 'BigDecimal.ToByteExact()'

Check warning on line 303 in src/Deveel.Math/Math/BigDecimal_Convertible.cs

View workflow job for this annotation

GitHub Actions / build (8.0.x, macos-latest) / build

Missing XML comment for publicly visible type or member 'BigDecimal.ToByteExact()'

Check warning on line 303 in src/Deveel.Math/Math/BigDecimal_Convertible.cs

View workflow job for this annotation

GitHub Actions / build (7.0.x, ubuntu-latest) / build

Missing XML comment for publicly visible type or member 'BigDecimal.ToByteExact()'

Check warning on line 303 in src/Deveel.Math/Math/BigDecimal_Convertible.cs

View workflow job for this annotation

GitHub Actions / build (8.0.x, ubuntu-latest) / build

Missing XML comment for publicly visible type or member 'BigDecimal.ToByteExact()'

Check warning on line 303 in src/Deveel.Math/Math/BigDecimal_Convertible.cs

View workflow job for this annotation

GitHub Actions / build (6.0.x, ubuntu-latest) / build

Missing XML comment for publicly visible type or member 'BigDecimal.ToByteExact()'

Check warning on line 303 in src/Deveel.Math/Math/BigDecimal_Convertible.cs

View workflow job for this annotation

GitHub Actions / build (6.0.x, windows-latest) / build

Missing XML comment for publicly visible type or member 'BigDecimal.ToByteExact()'

Check warning on line 303 in src/Deveel.Math/Math/BigDecimal_Convertible.cs

View workflow job for this annotation

GitHub Actions / build (8.0.x, windows-latest) / build

Missing XML comment for publicly visible type or member 'BigDecimal.ToByteExact()'

Check warning on line 303 in src/Deveel.Math/Math/BigDecimal_Convertible.cs

View workflow job for this annotation

GitHub Actions / build (7.0.x, windows-latest) / build

Missing XML comment for publicly visible type or member 'BigDecimal.ToByteExact()'
{
return (byte)ValueExact(8);
}

/**
* Returns this {@code BigDecimal} as a byte value if it has no fractional
* part and if its value fits to the byte range ([-128..127]). If these
Expand All @@ -410,9 +315,9 @@ public short ToInt16Exact()
* if rounding is necessary or the number doesn't fit in a byte.
*/

public byte ToByteExact()
public sbyte ToSByteExact()
{
return (byte)ValueExact(8);
return (sbyte)ValueExact(8);
}

/// <summary>
Expand Down Expand Up @@ -461,26 +366,49 @@ public float ToSingle()
return floatResult;
}

///**
//* Returns this {@code BigDecimal} as a double value. If {@code this} is too
//* big to be represented as an float, then {@code Double.POSITIVE_INFINITY}
//* or {@code Double.NEGATIVE_INFINITY} is returned.
//* <p>
//* Note, that if the unscaled value has more than 53 significant digits,
//* then this decimal cannot be represented exactly in a double variable. In
//* this case the result is rounded.
//* <p>
//* For example, if the instance {@code x1 = new BigDecimal("0.1")} cannot be
//* represented exactly as a double, and thus {@code x1.equals(new
//* BigDecimal(x1.ToDouble())} returns {@code false} for this case.
//* <p>
//* Similarly, if the instance {@code new BigDecimal(9007199254740993L)} is
//* converted to a double, the result is {@code 9.007199254740992E15}.
//* <p>
//*
//* @return this {@code BigDecimal} as a double value.
//*/
///**

Check warning on line 369 in src/Deveel.Math/Math/BigDecimal_Convertible.cs

View workflow job for this annotation

GitHub Actions / build (7.0.x, macos-latest) / build

XML comment is not placed on a valid language element

Check warning on line 369 in src/Deveel.Math/Math/BigDecimal_Convertible.cs

View workflow job for this annotation

GitHub Actions / build (6.0.x, macos-latest) / build

XML comment is not placed on a valid language element

Check warning on line 369 in src/Deveel.Math/Math/BigDecimal_Convertible.cs

View workflow job for this annotation

GitHub Actions / build (8.0.x, macos-latest) / build

XML comment is not placed on a valid language element

Check warning on line 369 in src/Deveel.Math/Math/BigDecimal_Convertible.cs

View workflow job for this annotation

GitHub Actions / build (7.0.x, ubuntu-latest) / build

XML comment is not placed on a valid language element

Check warning on line 369 in src/Deveel.Math/Math/BigDecimal_Convertible.cs

View workflow job for this annotation

GitHub Actions / build (8.0.x, ubuntu-latest) / build

XML comment is not placed on a valid language element

Check warning on line 369 in src/Deveel.Math/Math/BigDecimal_Convertible.cs

View workflow job for this annotation

GitHub Actions / build (6.0.x, ubuntu-latest) / build

XML comment is not placed on a valid language element

Check warning on line 369 in src/Deveel.Math/Math/BigDecimal_Convertible.cs

View workflow job for this annotation

GitHub Actions / build (6.0.x, windows-latest) / build

XML comment is not placed on a valid language element

Check warning on line 369 in src/Deveel.Math/Math/BigDecimal_Convertible.cs

View workflow job for this annotation

GitHub Actions / build (8.0.x, windows-latest) / build

XML comment is not placed on a valid language element

Check warning on line 369 in src/Deveel.Math/Math/BigDecimal_Convertible.cs

View workflow job for this annotation

GitHub Actions / build (7.0.x, windows-latest) / build

XML comment is not placed on a valid language element
//* Returns this {@code BigDecimal} as a double value. If {@code this} is too
//* big to be represented as an float, then {@code Double.POSITIVE_INFINITY}
//* or {@code Double.NEGATIVE_INFINITY} is returned.
//* <p>
//* Note, that if the unscaled value has more than 53 significant digits,
//* then this decimal cannot be represented exactly in a double variable. In
//* this case the result is rounded.
//* <p>
//* For example, if the instance {@code x1 = new BigDecimal("0.1")} cannot be
//* represented exactly as a double, and thus {@code x1.equals(new
//* BigDecimal(x1.ToDouble())} returns {@code false} for this case.
//* <p>
//* Similarly, if the instance {@code new BigDecimal(9007199254740993L)} is
//* converted to a double, the result is {@code 9.007199254740992E15}.
//* <p>
//*
//* @return this {@code BigDecimal} as a double value.
//*/

/// <summary>
/// Converts this <see cref="BigDecimal"/> to a <see cref="double"/>.
/// </summary>
/// <remarks>
/// <para>
/// If the <see cref="BigDecimal"/> is too big to be represented as an float,
/// then <see cref="Double.PositiveInfinity"/> or <see cref="Double.NegativeInfinity"/>
/// is returned.
/// </para>
/// <para>
/// Note, that if the unscaled value has more than 53 significant digits, then this decimal
/// cannot be represented exactly in a double variable. In this case the result is rounded.
/// </para>
/// <para>
/// For example, if the instance <c>x1 = BigDecimal.Parse("0.1")</c> cannot be
/// represented exactly as a double, and thus <c>x1.Equals(new BigDecimal(x1.ToDouble())</c>
/// returns <c>false</c> for this case.
/// </para>
/// <para>
/// Similarly, if the instance <c>new BigDecimal(9007199254740993L)</c> is converted to a
/// double, the result is <c>9.007199254740992E15</c>.
/// </para>
/// </remarks>
public double ToDouble()
{
int sign = Sign;
Expand Down
68 changes: 68 additions & 0 deletions src/Deveel.Math/Math/BigDecimal_Formattable.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
using System;
using System.Globalization;

namespace Deveel.Math
{
public sealed partial class BigDecimal : IFormattable
{
private const string GeneralStringFormat = "G";
private const string PlainStringFormat = "P";
private const string EngineeringStringFormat = "E";

/// <summary>
///
/// </summary>
/// <param name="format"></param>
/// <param name="provider"></param>
/// <remarks>
/// <para>
/// The supported formats are
/// <list type="bullet">
/// <listheader>
/// <term>Format</term>
/// <description>Description</description>
/// </listheader>
/// <item>
/// <term><c>G</c></term>
/// <description>General format. The number is formatted as a fixed-point number.</description>
/// </item>
/// <item>
/// <term><c>P</c></term>
/// <description>Plain format. The number is formatted as a plain number, without any scientific
/// notation. If the string representation is used to create a new instance, this instance is
/// generally not identical to this instance as the precision</description>
/// </item>
/// <item>
/// <term><c>E</c></term>
/// <description>Engineering format. The number is formatted as a fixed-point number in engineering
/// notation. If the scale is negative or if <c>scale - precision >= 6</c>
/// then engineering notation is used. Engineering notation is similar to the scientific notation except
/// that the exponent is made to be a multiple of 3 such that the integer part is lesser or equal to 1
/// and greater than 1000.</description>
/// </item>
/// </list>
/// </para>
/// </remarks>
/// <returns></returns>
/// <exception cref="ArgumentException"></exception>
public string ToString(string? format, IFormatProvider? provider = null)

Check warning on line 48 in src/Deveel.Math/Math/BigDecimal_Formattable.cs

View workflow job for this annotation

GitHub Actions / build (7.0.x, macos-latest) / build

The annotation for nullable reference types should only be used in code within a '#nullable' annotations context.

Check warning on line 48 in src/Deveel.Math/Math/BigDecimal_Formattable.cs

View workflow job for this annotation

GitHub Actions / build (7.0.x, macos-latest) / build

The annotation for nullable reference types should only be used in code within a '#nullable' annotations context.

Check warning on line 48 in src/Deveel.Math/Math/BigDecimal_Formattable.cs

View workflow job for this annotation

GitHub Actions / build (6.0.x, macos-latest) / build

The annotation for nullable reference types should only be used in code within a '#nullable' annotations context.

Check warning on line 48 in src/Deveel.Math/Math/BigDecimal_Formattable.cs

View workflow job for this annotation

GitHub Actions / build (6.0.x, macos-latest) / build

The annotation for nullable reference types should only be used in code within a '#nullable' annotations context.

Check warning on line 48 in src/Deveel.Math/Math/BigDecimal_Formattable.cs

View workflow job for this annotation

GitHub Actions / build (8.0.x, macos-latest) / build

The annotation for nullable reference types should only be used in code within a '#nullable' annotations context.

Check warning on line 48 in src/Deveel.Math/Math/BigDecimal_Formattable.cs

View workflow job for this annotation

GitHub Actions / build (8.0.x, macos-latest) / build

The annotation for nullable reference types should only be used in code within a '#nullable' annotations context.

Check warning on line 48 in src/Deveel.Math/Math/BigDecimal_Formattable.cs

View workflow job for this annotation

GitHub Actions / build (7.0.x, ubuntu-latest) / build

The annotation for nullable reference types should only be used in code within a '#nullable' annotations context.

Check warning on line 48 in src/Deveel.Math/Math/BigDecimal_Formattable.cs

View workflow job for this annotation

GitHub Actions / build (7.0.x, ubuntu-latest) / build

The annotation for nullable reference types should only be used in code within a '#nullable' annotations context.

Check warning on line 48 in src/Deveel.Math/Math/BigDecimal_Formattable.cs

View workflow job for this annotation

GitHub Actions / build (8.0.x, ubuntu-latest) / build

The annotation for nullable reference types should only be used in code within a '#nullable' annotations context.

Check warning on line 48 in src/Deveel.Math/Math/BigDecimal_Formattable.cs

View workflow job for this annotation

GitHub Actions / build (8.0.x, ubuntu-latest) / build

The annotation for nullable reference types should only be used in code within a '#nullable' annotations context.

Check warning on line 48 in src/Deveel.Math/Math/BigDecimal_Formattable.cs

View workflow job for this annotation

GitHub Actions / build (6.0.x, ubuntu-latest) / build

The annotation for nullable reference types should only be used in code within a '#nullable' annotations context.

Check warning on line 48 in src/Deveel.Math/Math/BigDecimal_Formattable.cs

View workflow job for this annotation

GitHub Actions / build (6.0.x, ubuntu-latest) / build

The annotation for nullable reference types should only be used in code within a '#nullable' annotations context.

Check warning on line 48 in src/Deveel.Math/Math/BigDecimal_Formattable.cs

View workflow job for this annotation

GitHub Actions / build (6.0.x, windows-latest) / build

The annotation for nullable reference types should only be used in code within a '#nullable' annotations context.

Check warning on line 48 in src/Deveel.Math/Math/BigDecimal_Formattable.cs

View workflow job for this annotation

GitHub Actions / build (6.0.x, windows-latest) / build

The annotation for nullable reference types should only be used in code within a '#nullable' annotations context.

Check warning on line 48 in src/Deveel.Math/Math/BigDecimal_Formattable.cs

View workflow job for this annotation

GitHub Actions / build (8.0.x, windows-latest) / build

The annotation for nullable reference types should only be used in code within a '#nullable' annotations context.

Check warning on line 48 in src/Deveel.Math/Math/BigDecimal_Formattable.cs

View workflow job for this annotation

GitHub Actions / build (8.0.x, windows-latest) / build

The annotation for nullable reference types should only be used in code within a '#nullable' annotations context.

Check warning on line 48 in src/Deveel.Math/Math/BigDecimal_Formattable.cs

View workflow job for this annotation

GitHub Actions / build (7.0.x, windows-latest) / build

The annotation for nullable reference types should only be used in code within a '#nullable' annotations context.

Check warning on line 48 in src/Deveel.Math/Math/BigDecimal_Formattable.cs

View workflow job for this annotation

GitHub Actions / build (7.0.x, windows-latest) / build

The annotation for nullable reference types should only be used in code within a '#nullable' annotations context.
{
if (provider == null)
provider = NumberFormatInfo.CurrentInfo;

if (String.IsNullOrWhiteSpace(format) ||
format == GeneralStringFormat)
{
return DecimalString.ToString(this, provider);
} else if (format == PlainStringFormat)
{
return DecimalString.ToPlainString(this, provider);
} else if (format == EngineeringStringFormat)
{
return DecimalString.ToEngineeringString(this, provider);
}

throw new ArgumentException($"Format '{format}' was not recognized");
}
}
}
Loading

0 comments on commit 0a7681f

Please sign in to comment.