Java just glossing over a decimal place? - java

So I'm trying to do a relatively simple program, but I am running into java's integer limits. The number is 471.5 billion. A friend suggested that I multiply 481.5 by 1000 a couple times in order to output the correct number. When I do this, the output is just 481 times 1000, no matter what I do.
As well, if I multiply by 1000 more than twice, It gives really odd numbers.
Here is the code
int debt1
debt1 = 481.5;
system.out.println(debt1 * 1000 * 1000 * 1000);

Are you sure your code even compiles correctly?
Your variable is defined as an int but you try to assign a double value to it.
If you change your variable type to double, it can hold the value 481.5 that you try to assign to it.
But in any case, if you want to deal with REALLY big numbers like 481.500.000.000, you should use BigInteger
Notice though that with BigInteger, you won't be able to simply write numbers in your IDE (since no built in java types can handle numbers this big). As the documentation says, you can create BigIntegers by either using a string representation of a number or by specifying the number in a couple more ways.
For a simple example take a look at this:
import java.math.BigInteger;
class Example {
public static void main(String[] args) {
BigInteger debt = new BigInteger("481500000000");
debt = debt.add(new BigInteger("12312"));
System.out.println(debt.toString());
}
}

Related

Adding large numbers while looping [duplicate]

in python with a simple loop you can calculate, let's say 600! it's a very very big number but python can easily take care of it in a fraction of a second.even it's more than 200 digit long.
in java in the other hand you are bound to 64bit literals (long data type). so the machine will return 0.
is there any way to overcome this?
You can use the Java BigInteger class.
And a simple example:
import java.math.BigInteger;
BigInteger k = BigInteger.valueOf(10000L);
k = k.pow(10000);
//k is now 10000^10000
System.out.println(k.toString());
It's important to know that the class is immutable. You can also look into the similar BigDecimal class for arbitrary precision signed decimal numbers.

Negative exponent at java.base/java.math.BigInteger.pow

How can i fix error Negative exponentat java.base/java.math.BigInteger.pow from my function:
static BigInteger eul(BigInteger n, BigInteger b) {
BigInteger pattern = (n.add(BigInteger.ONE)).divide(new BigInteger("4"));
BigInteger result = new BigInteger(String.valueOf(b.pow(pattern.intValue())));
return result;
}
error throw at line:
BigInteger result = new BigInteger(String.valueOf(b.pow(pattern.intValue())));
input
n=3214315236286878413828554688017932599492010774390476107169160882202257140006023
b=2424542564265464646464646412424987764446756457474245176752585282729789707797971262662662627967
output should be:
2012412197646109946818069059950164564377761312631574365459647649336933671988569
pattern.intValue()
pattern is some enormous number. .intValue() converts that to an int (hence the name), which is why this goes wrong, as this doesn't fit (and happens to turn into a negative number due to how intValue() works when you call that on a bigInteger whose value exceeds what int can represent. The reason only ints go there is because if you put a huge number there, your RAM can't hold it and your CPU would take a few million years to calculate it. There'd be no point.
How do I fix it?
By going back to whomever gave you this assignment. your code has a bug, but reading what it is intending to do, it is ((n+1)/4)^b.
Which is a number that has... a lot a lot of digits. Many, many more than what you expect for output.
Clearly that isn't what you really wanted, or if it is, no computer can calculate this, and the result would be nothing like what you wanted.
Possibly that output really is ((n+1)/4)^b, but mod something. Which the API does support: b.modPow(pattern, FigureOutWhatTheModuloIsAndPutThatHere).

Floats not adding up [duplicate]

I'm wondering what the best way to fix precision errors is in Java. As you can see in the following example, there are precision errors:
class FloatTest
{
public static void main(String[] args)
{
Float number1 = 1.89f;
for(int i = 11; i < 800; i*=2)
{
System.out.println("loop value: " + i);
System.out.println(i*number1);
System.out.println("");
}
}
}
The result displayed is:
loop value: 11
20.789999
loop value: 22
41.579998
loop value: 44
83.159996
loop value: 88
166.31999
loop value: 176
332.63998
loop value: 352
665.27997
loop value: 704
1330.5599
Also, if someone can explain why it only does it starting at 11 and doubling the value every time. I think all other values (or many of them at least) displayed the correct result.
Problems like this have caused me headache in the past and I usually use number formatters or put them into a String.
Edit: As people have mentioned, I could use a double, but after trying it, it seems that 1.89 as a double times 792 still outputs an error (the output is 1496.8799999999999).
I guess I'll try the other solutions such as BigDecimal
If you really care about precision, you should use BigDecimal
https://docs.oracle.com/javase/8/docs/api/java/math/BigDecimal.html
https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/math/BigDecimal.html
The problem is not with Java but with the good standard float's (http://en.wikipedia.org/wiki/IEEE_floating-point_standard).
You can either:
use Double and have a bit more precision (but not perfect of course, it also has limited precision)
use a arbitrary-precision-library
use numerically stable algorithms and truncate/round digits of which you are not sure they are correct (you can calculate numeric precision of operations)
When you print the result of a double operation you need to use appropriate rounding.
System.out.printf("%.2f%n", 1.89 * 792);
prints
1496.88
If you want to round the result to a precision, you can use rounding.
double d = 1.89 * 792;
d = Math.round(d * 100) / 100.0;
System.out.println(d);
prints
1496.88
However if you see below, this prints as expected, as there is a small amount of implied rounding.
It worth nothing that (double) 1.89 is not exactly 1.89 It is a close approximation.
new BigDecimal(double) converts the exact value of double without any implied rounding. It can be useful in finding the exact value of a double.
System.out.println(new BigDecimal(1.89));
System.out.println(new BigDecimal(1496.88));
prints
1.8899999999999999023003738329862244427204132080078125
1496.8800000000001091393642127513885498046875
Most of your question has been pretty well covered, though you might still benefit from reading the [floating-point] tag wiki to understand why the other answers work.
However, nobody has addressed "why it only does it starting at 11 and doubling the value every time," so here's the answer to that:
for(int i = 11; i < 800; i*=2)
╚═══╤════╝ ╚╤═╝
│ └───── "double the value every time"
│
└───── "start at 11"
You could use doubles instead of floats
If you really need arbitrary precision, use BigDecimal.
first of Float is the wrapper class for the primitive float
and doubles have more precision
but if you only want to calculate down to the second digit (for monetary purposes for example) use an integer (as if you are using cents as unit) and add some scaling logic when you are multiplying/dividing
or if you need arbitrary precision use BigDecimal
If precision is vital, you should use BigDecimal to make sure that the required precision remains. When you instantiate the calculation, remember to use strings to instantiate the values instead of doubles.
I never had a problem with simple arithmetic precision in either Basic, Visual Basic, FORTRAN, ALGOL or other "primitive" languages. It is beyond comprehension that JAVA can't do simple arithmetic without introducing errors. I need just two digits to the right of the decimal point for doing some accounting. Using Float subtracting 1000 from 1355.65 I get 355.650002! In order to get around this ridiculous error I have implemented a simple solution. I process my input by separating the values on each side of the decimal point as character, convert each to integers, multiply each by 1000 and add the two back together as integers. Ridiculous but there are no errors introduced by the poor JAVA algorithms.

Getting much higher precision with BigDecimal (or another class) in Java

I want to compute numbers with arbitrarily long decimal values (suppose I want to take a 100 decimal digits for a particular number).
//Take the square root of 2 for 100 digits in total.
public class Main {
public static void main(String[] args) {
BigDecimal root2 = new BigDecimal(Math.pow(2, 0.5));
root2 = root2.setScale(99, BigDecimal.ROUND_HALF_UP);
System.out.println(root2);
}
}
And this program outputs:
1.414213562373095145474621858738828450441360473632812500000000000000000000000000000000000000000000000
Having a beginner background in the storage of bytes, I realize the issue here is either the output format, or the fact that I'm still not getting the precision I'm looking for since it doesn't use the memory I'm expecting it to. Any suggestions? Is it possible to get precision this high? I'm not against turning to Mathematica.
For clarification: I'm trying to get the full precision of 100 digits (the zeros do not belong here).
Here is an explanation why what you are doing is not working.
Math.pow() returns a double. So your code is calculating the value using the precision provided by double, and then creating a BigDecimal from that double. It's too late to set the precision on the big decimal since it only has the double as input.
So you can not use Math.pow() for your purpose. Instead you need to find another library that does arbitrary precision calculations.
Refer to this question for more: Java's BigDecimal.power(BigDecimal exponent): Is there a Java library that does it?

Why does nextUp method in Math class skips some values?

I was just messing around with this method to see what it does. I created a variable with value 3.14 just because it came to my mind at that instance.
double n = 3.14;
System.out.println(Math.nextUp(n));
The preceding displayed 3.1400000000000006.
Tried with 3.1400000000000001, displayed the same.
Tried with 333.33, displayed 333.33000000000004.
With many other values, it displays the appropriate value for example 73.6 results with 73.60000000000001.
What happens to the values in between 3.1400000000000000 and 3.1400000000000006? Why does it skips some values? I know about the hardware related problems but sometimes it works right. Also even though it is known that precise operations cannot be done, why is such method included in the library? It looks pretty useless due to the fact that it doesn't work always right.
One useful trick in Java is to use the exactness of new BigDecimal(double) and of BigDecimal's toString to show the exact value of a double:
import java.math.BigDecimal;
public class Test {
public static void main(String[] args) {
System.out.println(new BigDecimal(3.14));
System.out.println(new BigDecimal(3.1400000000000001));
System.out.println(new BigDecimal(3.1400000000000006));
}
}
Output:
3.140000000000000124344978758017532527446746826171875
3.140000000000000124344978758017532527446746826171875
3.1400000000000005684341886080801486968994140625
There are a finite number of doubles, so only a specific subset of the real numbers are the exact value of a double. When you create a double literal, the decimal number you type is represented by the nearest of those values. When you output a double, by default, it is shown as the shortest decimal fraction that would round to it on input. You need to do something like the BigDecimal technique I used in the program to see the exact value.
In this case, both 3.14 and 3.1400000000000001 are closer to 3.140000000000000124344978758017532527446746826171875 than to any other double. The next exactly representable number above that is 3.1400000000000005684341886080801486968994140625
Floating point numbers are stored in binary: the decimal representation is just for human consumption.
Using Rick Regan's decimal to floating point converter 3.14 converts to:
11.001000111101011100001010001111010111000010100011111
and 3.1400000000000006 converts to
11.0010001111010111000010100011110101110000101001
which is indeed the next binary number to 53 significant bits.
Like #jgreve mentions this has to do due to the use of float & double primitives types in java, which leads to the so called rounding error. The primitive type int on the other hand is a fixed-point number meaning that it is able to "fit" within 32-bits. Doubles are not fixed-point, meaning that the result of double calculations must often be rounded in order to fit back into its finite representation, which leads sometimes (as presented in your case) to inconsistent values.
See the following two links for more info.
https://stackoverflow.com/a/322875/6012392
https://en.wikipedia.org/wiki/Double-precision_floating-point_format
A work around could be the following two, which gives a "direction" to the first double.
double n = 1.4;
double x = 1.5;
System.out.println(Math.nextAfter(n, x));
or
double n = 1.4;
double next = n + Math.ulp(n);
System.out.println(next);
But to handle floating point values it is recommended to use the BigDecimal class

Categories

Resources