Class DecimalFunctions

Object
Static
DecimalFunctions

public final class DecimalFunctions extends Static
Functions working on float and double values while taking in account their representation in base 10. Methods in this class may be helpful when used after parsing or before formatting a number in base 10: Methods in this class are usually not recommended for intermediate calculations, since base 10 is not more "real" than base 2 for natural phenomenon.
Since:
0.4
See Also:
  • Method Summary

    Modifier and Type
    Method
    Description
    static double
    Returns the difference between the given double value and the representation of that value in base 10.
    static boolean
    equals­Ignore­Missing­Fraction­Digits(double accurate, double approximate)
    Returns true if the given numbers or equal or differ only by accurate having more non-zero trailing decimal fraction digits than approximate.
    static double
    float­To­Double(float value)
    Converts the given float value to a double with the extra decimal fraction digits set to zero.
    static int
    floor­Log10(double x)
    Computes (int) floor(log10(x)).
    static int
    fraction­Digits­For­Delta(double accuracy, boolean strict)
    Returns the number of fraction digits needed for formatting in base 10 numbers of the given accuracy.
    static int
    Returns the number of significant fraction digits when formatting the given number in base 10.
    static int
    fraction­Digits­For­Value(double value, int uncertain­Digits)
    Returns the number of significant fraction digits, potentially minus trailing digits that may be rounding error.
  • Method Details

    • floatToDouble

      public static double floatToDouble(float value)
      Converts the given float value to a double with the extra decimal fraction digits set to zero. This is different than the standard cast in the Java language, which set the extra binary fraction digits to zero. For example, (double) 0.1f gives 0.10000000149011612 while float­To­Double(0.1f) returns 0.1.

      This method is equivalent to the following code, except that it is potentially faster because the actual implementation avoid to format and parse the value:

      return Double.parseDouble(Float.toString(value));
      

      Note on accuracy

      This method is not more accurate than the standard Java cast – it should be used only when the base 10 representation of the given value may be of special interest. If the value come from a call to Float​.parse­Float(String) (directly or indirectly), and if that call cannot be replaced by a call to Double​.parse­Double(String) (for example because the original String is not available anymore), then this method may be useful if one consider the String representation in base 10 as definitive. But if the value come from an instrument measurement or a calculation, then there is probably no reason to use this method because base 10 is not more "real" than base 2 or any other base for natural phenomenon.
      Parameters:
      value - the float value to convert as a double.
      Returns:
      the given value as a double with the extra decimal fraction digits set to zero.
    • deltaForDoubleToDecimal

      public static double deltaForDoubleToDecimal(double value)
      Returns the difference between the given double value and the representation of that value in base 10. For any value in the method's domain of validity (defined below), this method is approximately equivalent to the following code except that it is potentially faster since the actual implementation avoids the creation of Big­Decimal objects:
      BigDecimal base2  = new BigDecimal(value);     // Exact same value as stored in IEEE 754 format.
      BigDecimal base10 = BigDecimal.valueOf(value); // Exact same value as shown by println(value).
      return base10.subtract(base2).doubleValue();
      
      Computing value + delta­For­Double­To­Decimal(value) has no effect since the absolute value of the returned delta is always smaller than Math​.ulp(value) / 2. To see an effect, a type with more precision than the double type is necessary.

      Use case

      Many international standards define values in base 10. For example, the conversion factor from inches to centimetres is defined as exactly 2.54 cm/inch. This is by an internationally accepted definition since 1959, not an approximation. But the 2.54 value cannot be represented exactly in the IEEE 754 format – the error is approximately 3.6E-17 cm/inch. In the vast majority of cases such tiny error can be ignored. But in situations where it is desirable to have an error estimation (e.g. in non-linear equations where errors can grow exponentially), this method can be useful. Other examples of values defined in base 10 are conversions from feet to metres and map projection parameters defined by national mapping agencies.

      Domain of validity

      The current implementation cannot compute delta for abs(value) < 3E-8 approximately, except for the 0 value which is supported. For any non-zero value closer to zero than the 3E-8 threshold, this method returns Na­N because of insufficient algorithm accuracy. This limitation may change in any future SIS version if we find a better algorithm.
      Parameters:
      value - the value for which to get the delta compared to its base 10 representation.
      Returns:
      the delta that would need to be added to the given double value for getting a result closer to its base 10 representation, or Na­N if it cannot be computed.
    • fractionDigitsForDelta

      public static int fractionDigitsForDelta(double accuracy, boolean strict)
      Returns the number of fraction digits needed for formatting in base 10 numbers of the given accuracy. If the strict argument is true, then for any given accuracy this method returns a value n such as the difference between adjacent numbers formatted in base 10 with n fraction digits will always be equal or smaller than accuracy. Examples:
      • fraction­Digits­For­Delta(0.001, true) returns 3.
      • fraction­Digits­For­Delta(0.009, true) returns 3.
      • fraction­Digits­For­Delta(0.010, true) returns 2.
      • fraction­Digits­For­Delta(0.099, true) returns 3 (special case).

      Special cases:

      • If accuracy is Na­N or infinity, then this method returns 0 since those values are not represented by decimal digits.
      • If accuracy is 0, then this method returns 324 since 10-324 is the first power of 10 smaller than the minimal strictly positive double value (4.9E-324).
        Note: The above value can be understood in another way: if the first 324 fraction digits are zero, then the IEEE double value is guaranteed to be rounded to exactly 0 no matter what the next fraction digits are.
      • If accuracy is greater than 1, then this method returns the number of "unnecessary" trailing zeros as a negative number.
        Example: fraction­Digits­For­Delta(100, …) returns -2.
      • If the first non-zero digits of accuracy are equal or greater than 95 (e.g. 0.00099) and the strict argument is true, then this method increases the number of needed fraction digits in order to prevent the rounded number to be collapsed into the next integer value.
        Example: If accuracy is 0.95, then a return value of 1 is not sufficient since the rounded value of 0.95 with 1 fraction digit would be 1.0. Such value would be a violation of this method contract since the difference between 0 and that formatted value would be greater than the accuracy. Note that this is not an artificial rule; this is related to the fact that 0.9999… is mathematically strictly equals to 1.
      Invoking this method is equivalent to computing (int) -floor(log10(accuracy)) except for the 0, Na­N, infinities and 0.…95 special cases.
      Parameters:
      accuracy - the desired accuracy of numbers to format in base 10.
      strict - true for checking the 0.…95 special case. If false, then the difference between adjacent formatted numbers is not guaranteed to be smaller than accuracy in every cases.
      Returns:
      number of fraction digits needed for formatting numbers with the given accuracy. May be negative.
      See Also:
    • fractionDigitsForValue

      public static int fractionDigitsForValue(double value)
      Returns the number of significant fraction digits when formatting the given number in base 10. This method does not ignore trailing zeros. For example, fraction­Digits­For­Value(1.0) returns 16, because the double format can store almost 16 decimal digits after 1.
      Note: We said almost because the very last digit may be able to store only a subset of the [0 … 9] digits.
      Invoking this method is equivalent to invoking fraction­Digits­For­Delta(Math.ulp(value), false), except that it is potentially faster.

      Special cases:

      • If value is Na­N or infinity, then this method returns 0 since those values are not represented by decimal digits.
      • If value is 0, then this method returns 324 since Math​.ulp(0) = 4.9E-324.

      Example

      This method is useful with Number­Format for formatting all significant digits of a double value, padding with trailing zeros if necessary, but no more than necessary.
      Parameters:
      value - the value for which to get the number of significant fraction digits.
      Returns:
      the number of significant fraction digits (may be negative), or 0 if value is NaN or infinity.
      See Also:
    • fractionDigitsForValue

      public static int fractionDigitsForValue(double value, int uncertainDigits)
      Returns the number of significant fraction digits, potentially minus trailing digits that may be rounding error. First, this method gets the number of fraction digits as of fraction­Digits­For­Value(double). Then there is a choice:
      • If after rounding the given value to an amount of fraction digits given by (fraction­Digits - uncertain­Digits) the 4 last fraction digits before the rounded ones are zero, then this method returns fraction­Digits - uncertain­Digits.
      • Otherwise this method returns fraction­Digits.
      The threshold of 4 trailing fraction digits is arbitrary and may change in any future SIS version.

      Examples

      • fraction­Digits­For­Value(179.12499999999824) returns 14, the amount of digits after the decimal separator.
      • fraction­Digits­For­Value(179.12499999999824, 3) returns 11 because rounding the 3 last digits (i.e. rounding after the 11th digit) results in 179.125000000000. Since the 4 last fraction digits are zero, the condition for allowing that rounding is met.
      • fraction­Digits­For­Value(179.12499999999824, 2) returns 14 because rounding the 2 last digits (i.e. rounding after the 12th digit) results in 179.124999999998. The condition for 4 trailing zero fraction digits is not met.
      • fraction­Digits­For­Value(179.12499997999999, 3) returns 14 because rounding the 3 last digits results in 179.12499997000. The condition for 4 trailing zero fraction digits is not met.
      Parameters:
      value - the value for which to get the number of significant fraction fraction digits minus rounding error.
      uncertain­Digits - number of trailing fraction digits which may be rounding error artefacts.
      Returns:
      suggested number of significant digits (may be negative), or 0 if value is NaN or infinity.
    • floorLog10

      public static int floorLog10(double x)
      Computes (int) floor(log10(x)). For values greater than one, this is the number of digits - 1 in the decimal representation of the given number. For values smaller than one, this is the number of fraction digits required for showing the first non-zero decimal digit.
      Parameters:
      x - the value for which to compute the logarithm. Must be greater than zero.
      Returns:
      logarithm of the given value, rounded toward zero.
      Throws:
      Arithmetic­Exception - if the given value is zero, negative, infinity or NaN.
      Since:
      1.0
      See Also:
    • equalsIgnoreMissingFractionDigits

      public static boolean equalsIgnoreMissingFractionDigits(double accurate, double approximate)
      Returns true if the given numbers or equal or differ only by accurate having more non-zero trailing decimal fraction digits than approximate.
      Examples
      Accurate Approximate Result Comment
      0.123456 0.123 true Differ in digits not specified by approximate.
      0.123456 0.123000 true This method cannot distinguish missing digits from trailing zeros.
      0.123456 0.123001 false No missing digits, and some of them differ.
      0.123 0.123456 false approximate and accurate cannot be interchanged.

      Use case

      this method is useful when approximate is a number parsed by Double​.parse­Double(String) and the data producer may have rounded too many fraction digits when formatting the numbers. In some cases we can suspect what the real value may be and want to ensure that a replacement would not contradict the provided value. This happen for example in Well Known Text format, where the following element is sometimes written with the conversion factor rounded:
      AngleUnit["degree", 0.017453292519943295]      // Expected
      AngleUnit["degree", 0.01745329252]             // Given by some providers
      
      Parameters:
      accurate - the most accurate number.
      approximate - the number which may have missing decimal fraction digits.
      Returns:
      whether the two number are equal, ignoring missing decimal fraction digits in approximate.
      Since:
      1.0