Package org.apache.sis.math
Class DecimalFunctions

public final class DecimalFunctions extends Static
Functions working onfloat
anddouble
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: Postparsing methods
floatToDouble(float)
anddeltaForDoubleToDecimal(double)
: for compensating error when the base 10 representation is considered definitive.
 Preformatting methods
fractionDigitsForValue(double)
andfractionDigitsForDelta(double, boolean)
: for formatting numbers using the exact amount of significant digits for a given precision.
 Since:
 0.4
 See Also:
MathFunctions.pow10(int)
,Math.log10(double)
Defined in the
sisutility
module  Postparsing methods


Method Summary
All Methods Static Methods Concrete Methods Modifier and Type Method Description static double
deltaForDoubleToDecimal(double value)
Returns the difference between the givendouble
value and the representation of that value in base 10.static boolean
equalsIgnoreMissingFractionDigits(double accurate, double approximate)
Returnstrue
if the given numbers or equal or differ only byaccurate
having more nonzero trailing decimal fraction digits thanapproximate
.static double
floatToDouble(float value)
Converts the givenfloat
value to adouble
with the extra decimal fraction digits set to zero.static int
floorLog10(double x)
Computes(int) floor(log10(x))
.static int
fractionDigitsForDelta(double accuracy, boolean strict)
Returns the number of fraction digits needed for formatting in base 10 numbers of the given accuracy.static int
fractionDigitsForValue(double value)
Returns the number of significant fraction digits when formatting the given number in base 10.static int
fractionDigitsForValue(double value, int uncertainDigits)
Returns the number of significant fraction digits, potentially minus trailing digits that may be rounding error.



Method Detail

floatToDouble
public static double floatToDouble(float value)
Converts the givenfloat
value to adouble
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 whilefloatToDouble(0.1f)
returns 0.1.Note: 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 toThis method is equivalent to the following code, except that it is potentially faster since the actual implementation avoid to format and parse the value:Float.parseFloat(String)
(directly or indirectly), and if that call can not be replaced by a call toDouble.parseDouble(String)
(for example because the originalString
is not available anymore), then this method may be useful if one consider theString
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.return Double.parseDouble(Float.toString(value));
 Parameters:
value
 thefloat
value to convert as adouble
. 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 givendouble
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 ofBigDecimal
objects:
ComputingBigDecimal 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();
value + deltaForDoubleToDecimal(value)
has no effect since the absolute value of the returned delta is always smaller thanMath.ulp(value) / 2
. To see an effect, a type with more precision than thedouble
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 can not be represented exactly in the IEEE 754 format – the error is approximately 3.6E17 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 nonlinear 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 validityThe current implementation can not compute delta forabs(value) < 3E8
approximately, except for the 0 value which is supported. For any nonzero value closer to zero than the 3E8 threshold, this method returnsNaN
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, orNaN
if it can not 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 thestrict
argument istrue
, then for any givenaccuracy
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 thanaccuracy
. Examples:fractionDigitsForDelta(0.001, true)
returns 3.fractionDigitsForDelta(0.009, true)
returns 3.fractionDigitsForDelta(0.010, true)
returns 2.fractionDigitsForDelta(0.099, true)
returns 3 (special case).
Special cases:
 If
accuracy
isNaN
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 positivedouble
value (4.9E324).Note: The above value can be understood in an other way: if the first 324 fraction digits are zero, then the IEEEdouble
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:fractionDigitsForDelta(100, …)
returns 2.  If the first nonzero digits of
accuracy
are equal or greater than 95 (e.g. 0.00099) and thestrict
argument istrue
, 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: Ifaccuracy
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.
(int) floor(log10(accuracy))
except for the 0,NaN
, infinities and0.…95
special cases. Parameters:
accuracy
 the desired accuracy of numbers to format in base 10.strict
true
for checking the0.…95
special case. Iffalse
, then the difference between adjacent formatted numbers is not guaranteed to be smaller thanaccuracy
in every cases. Returns:
 number of fraction digits needed for formatting numbers with the given accuracy. May be negative.
 See Also:
NumberFormat.setMaximumFractionDigits(int)

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 examplefractionDigitsForValue(1.0)
returns 16, because thedouble
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 invokingfractionDigitsForDelta(Math.ulp(value), false)
, except that it is potentially faster.Special cases:
 If
value
isNaN
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 sinceMath.ulp(0)
= 4.9E324.
Example: This method is useful withNumberFormat
for formatting all significant digits of adouble
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:
NumberFormat.setMinimumFractionDigits(int)
 If

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 offractionDigitsForValue(double)
. Then there is a choice: If after rounding the given
value
to an amount of fraction digits given by (fractionDigits
uncertainDigits
) the 4 last fraction digits before the rounded ones are zero, then this method returnsfractionDigits
uncertainDigits
.  Otherwise this method returns
fractionDigits
.
Note: The threshold of 4 trailing fraction digits is arbitrary and may change in any future SIS version.Examples:fractionDigitsForValue(179.12499999999824)
returns 14, the amount of digits after the decimal separator.fractionDigitsForValue(179.12499999999824, 3)
returns 11 because rounding the 3 last digits (i.e. rounding after the 11^{th} digit) results in 179.125000000000. Since the 4 last fraction digits are zero, the condition for allowing that rounding is met.fractionDigitsForValue(179.12499999999824, 2)
returns 14 because rounding the 2 last digits (i.e. rounding after the 12^{th} digit) results in 179.124999999998. The condition for 4 trailing zero fraction digits is not met.fractionDigitsForValue(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.uncertainDigits
 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.
 If after rounding the given

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 nonzero 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:
ArithmeticException
 if the given value is zero, negative, infinity or NaN. Since:
 1.0
 See Also:
MathFunctions.pow10(int)

equalsIgnoreMissingFractionDigits
public static boolean equalsIgnoreMissingFractionDigits(double accurate, double approximate)
Returnstrue
if the given numbers or equal or differ only byaccurate
having more nonzero trailing decimal fraction digits thanapproximate
.Examples Accurate Approximate Result Comment 0.123456 0.123 true Differ in digits not specified by approximate
.0.123456 0.123000 true This method can not 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
andaccurate
can not be interchanged.Use case: this method is useful whenapproximate
is a number parsed byDouble.parseDouble(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 sometime 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

