Validate if big decimal is created without any precision loss - double

I have a method which accepts BigDecimal. I want to make sure its decimal value have no precision loss (i.e) input to big decimal is exactly stored as it is. My understanding is that precision loss happens when I try to convert infinite double to big decimal and so, it is recommended to create big decimal using string representation of double. Basically, I want to make sure if big decimal is constructed using BigDecimal(String) for such infinite doubles.
As per my understanding after going through doc, input double value which results in precision loss during big decimal conversion always have very large magnitude which won't fit in 64 bits. Example: 0.1. So, string and double value representation of such big decimals won't match. is it enough to say that precision loss has occurred when string and double value won't match?
Eg:
BigDecimal decimal = new BigDecimal(0.1);
System.out.println(decimal.toString()) // prints 0.1000000000000000055511151231257827021181583404541015625
System.out.println(decimal.doubleValue()) // prints 0.1.
String and double value of big decimal differ and so, precision loss happened.

This idea breaks down if you allow the BigDecimal to be the result of arithmetic.
If you are going to require the BigDecimal to be the direct, unmodified result of conversion of a decimal string it would be much simpler to require a String argument and convert it to BigDecimal in your method.
The following program is an attempt to implement and test your validity check. The variable third was calculated without any involvement of doubles, using only decimal strings and BigDecimal, but fails the test.
import java.math.BigDecimal;
import java.math.RoundingMode;
public strictfp class Test {
public static void main(String[] args) {
BigDecimal third = BigDecimal.ONE.divide(new BigDecimal("3"), 30, RoundingMode.HALF_EVEN);
testIt(new BigDecimal("0.1"));
testIt(new BigDecimal(0.1));
testIt(third);
}
static void testIt(BigDecimal in) {
System.out.println(in+" "+isValid(in));
}
static boolean isValid(BigDecimal in) {
double d = in.doubleValue();
String s1 = in.toString();
String s2 = Double.toString(d);
return s1.equals(s2);
}
}
Output:
0.1 true
0.1000000000000000055511151231257827021181583404541015625 false
0.333333333333333333333333333333 false

Related

Converting a double to a long, then back to double?

Does Converting a double to a long, then back to double, guarantees keeping the exact value to the left of the decimal point?
EDIT:
Working with C++: Conversion is as follows:
double d_var = func();
long l_var = (long)d_var;
d_var = (double)l_var;
For every programming language I have worked with it will keep the value to the left of the decimal point.
For typecast then the fractions are removed when casting, but for range then double can hold bigger numbers than long and therefore becomes something else during a typecast.
At least for common languages I can think of.

Multiplying two double value gives negative number in flutter

I need to multiply two large numbers for example,
double x = 318191400000;
double result =x*x;
But i am getting negative value for this when building in flutter .
Please help me on this.
[1]: https://i.stack.imgur.com/eyxJ4.png
You're not actually multiplying two doubles here, but two ints which is overflowing the 64-bit integer resulting in a negative number.
With doubles:
void main() {
double x = 318191400000;
print(x*x); // Result: 1.0124576703396e+23
}
With ints:
void main() {
int x = 318191400000;
print(x*x); // Result: -8411186631728820224
}
If you ever print a double to the console, you'll always see it displayed in either scientific notation (for extremely large or small values) or with a decimal point with at least one trailing digit.
Finally i have found solution and sharing here for anyone having these kind of issues,
xValues[index].toDouble() * yValues[index].toDouble()
This gives the expected result which is 1.0124576703396e+23

Scala: Converting a Double from Scientific Notation without losing precision?

I'd like to convert a double such as 1.1231053E7 to 11,231,053.0 in scala. Currently the way I am converting doubles is to do this f"$number" where number is a double value. Unfortunately this just gives me a string with 1.1231053E7.
I can convert it out of scientific notation using NumberFormat or DecimalFormat but these also force me to choose a predetermined precision. I want flexible precision. So...
val number1 = 1.2313215
val number2 = 100
val number4 = 3.333E2
... when converted should be...
1.2313215
100
333.3
Currently DecimalFormat makes me choose the precision during construction like so: new DecimalFormat(##.##). Each # after . signifies a decimal point.
If I use f"$number", it treats the decimal points correctly but, like I said before, it is unable to handle the scientific notation.
Just decide how many places after the . you need, write out the number hiding the zeros:
val fmt = new java.text.DecimalFormat("#,##0.##############")
for (x <- List[Double](1.2313215, 100, 3.333E2)) println(fmt.format(x))
prints:
1.2313215
100
333.3

Why is 0.29999999999999998 converted to 0.3?

How does it work internally?
How does it decide to convert 0.29999999999999998 to 0.3, even though 0.3 cannot be represented in binary?
Here are some more example:
scala> 0.29999999999999998
res1: Double = 0.3
scala> 0.29999999999999997
res2: Double = 0.3
scala> 0.29999999999999996
res3: Double = 0.29999999999999993
scala> 0.29999999999999995
res4: Double = 0.29999999999999993
There are two conversions involved.
First 0.29999999999999998 is converted to 0.299999999999999988897769753748434595763683319091796875, the nearest representable number.
Next, 0.299999999999999988897769753748434595763683319091796875 is converted to decimal for printing. 0.3 is also one of the numbers that converts to 0.299999999999999988897769753748434595763683319091796875, and it is the one that gets printed because it is so short.
Every finite double number is exactly representable as a decimal fraction. Generally, default output does not attempt to print the exact value, because it can be very long - far longer than the example above. A common choice is to print the shortest decimal fraction that would convert to the double on input. Both conversions are done using non-trivial algorithms. See Algorithm to convert an IEEE 754 double to a string? for some discussion and references to output algorithms.
==============================================================
There has been some discussion in comments on the value 0.30000000000000004. I agree with the comments by Rick Regan and Jesper, but thought it might be useful to add to this answer.
The exact value of the closest double to 0.30000000000000004 is 0.3000000000000000444089209850062616169452667236328125. All decimal numbers in the range [0.3000000000000000166533453693773481063544750213623046875, 0.3000000000000000721644966006351751275360584259033203125] convert to that value, and no numbers even slightly outside that range do so. 0.3000000000000000 is outside the range, so it does not have enough digits. 0.30000000000000004 is inside the range, so there is no need for more digits to correctly identify the double.
Note in Scala Double (see IEEE 754 Standard and IEEE Floating-Point Arithmetic), the original declared value is rounded up to nearest,
val x = 0.29999999999999998
x: Double = 0.3
"0.29999999999999998".toDouble
Double = 0.3
in as much as
0.2999999999999999999999999999999999999999999999999999999999998
Double = 0.3
Also in BigDecimal for arbitrary precision decimal floating-point representation (see API), the original value of type Double (parameter to the constructor) is first rounded up, namely
BigDecimal(0.29999999999999998) == 0.3
Boolean = true
BigDecimal(0.29999999999999998)
scala.math.BigDecimal = 0.3
However a textual declaration of the original value is not interpreted as Double and hence rounded up,
BigDecimal("0.29999999999999998") == 0.3
Boolean = false
namely,
BigDecimal("0.29999999999999998")
scala.math.BigDecimal = 0.29999999999999998

Double numbers and bitxor [duplicate]

This question already has answers here:
How to use Bitxor for Double Numbers?
(2 answers)
Closed 9 years ago.
I have two matrices a = [120.23, 255.23669877,...] and b = [125.000083, 800.0101010,...] with double numbers in [0, 999]. I want to use bitxor for a and b. I can not use bitxor with round like this:
result = bitxor(round(a(1,j),round(b(1,j))
Because the decimal parts 0.23 and 0.000083 ,... are very important to me. I thought maybe I could do a = a*10^k and b = b*10^k and use bitxor and after that result/10^k (because I want my result's range to also be [0, 999]. But I do not know the maximum length of the number after the decimal point. Does k = 16 support the max range of double numbers in Matlab? Does bitxor support two 19-digit numbers? Is there a better solution?
This is not really an answer, but a very long comment with embedded code. I don't have a current matlab installation, and in any case don't know enough to answer the question in that context. Instead, I've written a Java program that I think may do what you are asking for. It uses two Java classes, BigInteger and BigDecimal. BigInteger is an extended integer format. BigDecimal is the combination of a BigInteger and a decimal scale.
Conversion from double to BigDecimal is exact. Conversion in the opposite direction may require rounding.
The function xor in my program converts each of its operands to BigDecimal. It finds a number of decimal digits to move the decimal point by to make both operands integers. After scaling, it converts to BigInteger, does the actual xor, and converts back to BigDecimal undoing the scaling.
The main point of this is for you to look at the results, and see whether they are what you want, and would be useful to you if you could do the same thing in Matlab. Explaining any ways in which the results are not what you want may help clarify your requirements for the Matlab experts.
Here is some test output. The top and bottom rows of each block are in decimal. The middle row is the scaled integer versions of the inputs, in hex.
Testing operands 1.100000000000000088817841970012523233890533447265625, 2
2f0a689f1b94a78f11d31b7ab806d40b1014d3f6d59 xor 558749db77f70029c77506823d22bd0000000000000 = 7a8d21446c63a7a6d6a61df88524690b1014d3f6d59
1.1 xor 2.0 = 2.8657425494106605
Testing operands 100, 200.0004999999999881765688769519329071044921875
2cd76fe086b93ce2f768a00b22a00000000000 xor 59aeee72a26b59f6380fcf078b92c4478e8a13 = 7579819224d26514cf676f0ca932c4478e8a13
100.0 xor 200.0005 = 261.9771865509636
Testing operands 120.3250000000000028421709430404007434844970703125, 120.75
d2c39898113a28d484dd867220659fbb45005915 xor d3822c338b76bab08df9fee485d1b00000000000 = 141b4ab9a4c926409247896a5b42fbb45005915
120.325 xor 120.75 = 0.7174277813579485
Testing operands 120.2300000000000039790393202565610408782958984375, 120.0000830000000036079654819332063198089599609375
d298ff20fbed5fd091d87e56002df79fc7007cb7 xor d231e5f39e1db18654cb8c43d579692616a16a1f = a91ad365f0ee56c513f215d5549eb9d1a116a8
120.23 xor 120.000083 = 0.37711627930683345
Here is the Java program:
import java.math.BigDecimal;
import java.math.BigInteger;
public class Test {
public static double xor(double a, double b) {
BigDecimal ad = new BigDecimal(a);
BigDecimal bd = new BigDecimal(b);
/*
* Shifting the decimal point right by scale will make both operands
* integers.
*/
int scale = Math.max(ad.scale(), bd.scale());
/*
* Scale both operands by, in effect, multiplying by the same power of 10.
*/
BigDecimal aScaled = ad.movePointRight(scale);
BigDecimal bScaled = bd.movePointRight(scale);
/*
* Convert the operands to integers, treating any rounding as an error.
*/
BigInteger aInt = aScaled.toBigIntegerExact();
BigInteger bInt = bScaled.toBigIntegerExact();
BigInteger resultInt = aInt.xor(bInt);
System.out.println(aInt.toString(16) + " xor " + bInt.toString(16) + " = "
+ resultInt.toString(16));
/*
* Undo the decimal point shift, in effect dividing by the same power of 10
* as was used to scale to integers.
*/
BigDecimal result = new BigDecimal(resultInt, scale);
return result.doubleValue();
}
public static void test(double a, double b) {
System.out.println("Testing operands " + new BigDecimal(a) + ", " + new BigDecimal(b));
double result = xor(a, b);
System.out.println(a + " xor " + b + " = " + result);
System.out.println();
}
public static void main(String arg[])
{
test(1.1, 2.0);
test(100, 200.0005);
test(120.325, 120.75);
test(120.23, 120.000083);
}
}
"But I do not know the max length of number after point ..."
In double precision floating-point you have 15–17 significant decimal digits. If you give bitxor double inputs these must be less than intmax('uint64'): 1.844674407370955e+19. The largest double, realmax (= 1.797693134862316e+308), is much bigger than this, so you can't represent everything in the the way you're using. For example, this means that your value of 800.0101010*10^17 won't work.
If your range is [0, 999], one option is to solve for the largest fractional exponent k and use that: log(double(intmax('uint64'))/999)/log(10) (= 16.266354234268810).