BigDecimal.intValue() returns Unexpected Number - java

I'm running into a strange java bug using the intValue() from the BigDecimal class.
I'm starting with a value of 3300028000.
When I call the following code:
int i = d.intValue();
it returns: -994939296
Any ides as to why this would happen?

An int can't hold a value that big, so it overflows. Try using a long.

When you try to fit this number into an int variable, it overflows, since the int type in Java has 32 bits, ergo an int variable can store values that range from −2,147,483,648 to 2,147,483,647.
To store the value of your BigInteger, you have to use a long variable. Try this:
long value = d.longValue();

What would you like it to return? :)
As described in the javadocs:
if the resulting "BigInteger" is too big to fit in an int, only the
low-order 32 bits are returned
intValueExact, on the other hand, would throw an exception.

You should really read Java API before blaming it:
Converts this BigDecimal to an int. This conversion is analogous to
the narrowing primitive conversion from double to short as defined in
section 5.1.3 of The Java™ Language Specification: any fractional part
of this BigDecimal will be discarded, and if the resulting
"BigInteger" is too big to fit in an int, only the low-order 32 bits
are returned. Note that this conversion can lose information about the
overall magnitude and precision of this BigDecimal value as well as
return a result with the opposite sign.

I don't know why you need the int value of a BigDecimal but the class BigDecimal contains lots of methods to fit your request.
compareTo
add
substract
multiply
divide
etc..
I would work with BigDecimal itself. Sooner or later; Converting the BigDecimal type to other primitive types will end up with an error. Cuz all of them has a limit.

Related

Why casting a very large long number to int gives us a strange output (Java)?

I was practicing some castings in Java and I faced a situation for which I couldn't find any answers, anywhere. There are a lot of similar questions with answers, but none gave me an explanation for this particular case.
When I do something like
long l = 165787121844687L;
int i = (int) l;
System.out.println("long: " + l);
System.out.println("after casting to int: " + i);
The output is
long: 165787121844687
after casting to int: 1384219087
This result is very intriguing for me.
I know that the type long is a 64-bit integer, and the type int is a 32-bit integer. I also know that when we cast a larger type to a smaller one, we can lose information. And I know that there is a Math.toIntExact() method that is quite useful.
But what's the explanation for this "1384219087" output? There was loss of data, but why this number? How "165787121844687" became "1384219087"? Why does the code even compile?
That's it. Thanks!
165787121844687L in hex notation = 0000 96C8 5281 81CF
1384219087 in hex notation = 5281 81CF
So the cast truncated the top 32 bits as expected.
32-bits
deleted
▼▼▼▼ ▼▼▼▼
165_787_121_844_687L = 0000 96C8 5281 81CF ➣ 1_384_219_087
64-bit long ▲▲▲▲ ▲▲▲▲ 32-bit int
   32-bits
remaining
If you convert these two numbers to hexadecimal, you get
96C8528181CF
528181CF
See what's happened here?
The Answer by OldProgrammer is correct, and should be accepted. Here is some additional info, and a workaround.
Java spec says so
Why does the code even compile?
When you cast a numeric primitive in Java, you take responsibility for the result including the risk of information loss.
Why? Because the Java spec says so. Always best to read the documentation. Programming by intuition is risky business.
See the Java Language Specification, section 5.1.3. Narrowing Primitive Conversion. To quote (emphasis mine):
A narrowing primitive conversion may lose information …
A narrowing conversion of a signed integer to an integral type T simply discards all but the n lowest order bits, where n is the number of bits used to represent type T. In addition to a possible loss of information about the magnitude of the numeric value, this may cause the sign of the resulting value to differ from the sign of the input value.
Math#…Exact…
When you want to be alerted to data loss during conversion from a long to a short, use the Math methods for exactitude. If the operation overflows, an execution is thrown. You can trap for that exception.
try
{
int i = Math.toIntExact( 165_787_121_844_687L ) ; // Convert from a `long` to an `int`.
}
catch ( ArithmeticException e )
{
// … handle conversion operation overflowing an `int` …
}
You will find similar Math#…Exact… methods for absolute value, addition, decrementing, incrementing, multiplying, negating, and subtraction.

Number too big for BigInteger

I'm developing a chemistry app, and I need to include the Avogadro's number:
(602200000000000000000000)
I don't really know if I can use scientific notation to represent it as 6.022 x 10x23 (can't put the exponent).
I first used double, then long and now, I used java.math.BigInteger.
But it still says it's too big, what can I do or should this is just to much for a system?
Pass it to the BigInteger constructor as a String, and it works just fine.
BigInteger a = new BigInteger("602200000000000000000000");
a = a.multiply(new BigInteger("2"));
System.out.println(a);
Output: 1204400000000000000000000
First of all, you need to check your physics / chemistry text book.
Avogadro's number is not 602,200,000,000,000,000,000,000. It is approximately 6.022 x 1023. The key word is "approximately". As of 2019, the precise value is 6.02214076×1023 mol−1
(In 2015 when I originally wrote this reply, the current best approximation for Avogadro's number was 6.022140857(74)×1023 mol−1, and the relative error was +/- 1.2×10–8. In 2019, the SI redefined the mole / Avogadro's number to be the precise value above. Source: Wikipedia)
My original (2015) answer was that since the number only needed 8 decimal digits precision, the Java double type was an appropriate type to represent it. Hence, I recommended:
final double AVOGADROS_CONSTANT = 6.02214076E23;
Clearly, neither int or long can represent this number. A float could, but not with enough precision (assuming we use the best available measured value).
Now (post 2019) the BigInteger is the simplest correct representation.
Now to your apparent problems with declaring the constant as (variously) an double, a long and a BigInteger.
I expect you did something like this:
double a = 602200000000000000000000;
and so on. That isn't going to work, but the reason it won't work needs to be explained. The problem is that the number is being supplied as an int literal. An int cannot be that big. The largest possible int value is 231 - 1 ... which is a little bit bigger than 2 x 109.
That is what the Java compiler was complaining about. The literal is too big to be an int.
It is too big for long literal as well. (Do the math.)
But it is not too big for a double literal ... provided that you write it correctly.
The solution using BigInteger(String) works because it side-steps the problem of representing the number as a numeric literal by using a string instead, and parsing it at runtime. That's OK from the perspective of the language, but (IMO) wrong because the extra precision is an illusion.
You can use E notation to write the scientific notation:
double a = 6.022e23;
The problem is with how you're trying to create it (most likely), not because it can't fit.
If you have just a number literal in your code (even if you try to assign it to a double or long), this is first treated as an integer (before being converted to the type it needs to be), and the number you have can't fit into an integer.
// Even though this number can fit into a long, it won't compile, because it's first treated
// as an integer.
long l = 123456788901234;
To create a long, you can add L to your number, so 602200000000000000000000L, although it won't fit into a long either - the max value is 263-1.
To create a double, you can add .0 to your number, so 602200000000000000000000.0 (or 6.022e23 as Guffa suggested), although you should not use this if you want precise values, as you may lose some accuracy because of the way it stores the value.
To create a BigInteger, you can use the constructor taking a string parameter:
new BigInteger("602200000000000000000000");
Most probably you are using long to initialize BigInteger. Since long can represent 64-bit numbers, your number would be too big to fit in to long. Using String would help.

Storing large decimal numbers in Java

I need to store 17774132 in a double format,
but it seems that double is to small since I get 1.7774132E7.
How can I overcome this problem? I need some kind of primitive that can hold it with floating point.
Thank you
In java if you want accurate calculations for large numbers with fractions, you should use java.math.BigDecimal class. The integer counterpart is java.math.BigInteger.
Also I think double can accomodate 17774132, it's just showing the value in something called as "E Notation" which a Scientific notation to denote numbers. Refer to this : http://en.wikipedia.org/wiki/Scientific_notation#E_notation
Remeber that means 1.7774132 * 10^7, so the value is represented by:
1.7774132 * 10000000
That's a big number, don't you think?
Java outputs by default on scientific notation if needed. Big numbers like that are expressed in scientific notation.
1.7774132E7 is exactly the same as 17774132. It's just displayed in scientific notation. A double is more than capable of holding this value. As others have said, though, use BigDecimal if you're worried about size or accuracy.
First, hopefully you recognize the issues with floating-point decimal representations.
17774132 is equivalent to 1.7774132E7; the "E7" means it is being multiplied by 10^7. If your issue is that you want it displayed differently, you can use a NumberFormat.
Note that 17774132 is actually an integer and well below the threshold of ~2.1 billion for the int primitive type. The long primitive type lets you go even higher if you are actually using integers.
If you want to represent the number differently and it is not an integer, you can try BigDecimal (or BigInteger for legitimate integers too big for a long).

number too large

Hey , i hope i get help with this.
im a coder of a rsps (runescape private server)
and in this game you could like have items and weapons
and the max anmount of a item you can have is 2147000000
and i can change the amount of the max by changing this int
public int maxItemAmount = 2147000000;
and it works
but i want to make it like 3000000000
and i do this
public int maxItemAmount = 3000000000;
and when i compile i get this error
integrer number too large: 3000000000
please guys help me out if you can :)
Integer has an upper bound of 2^31 (2147483648). If you want numbers longer than that, you can use a long or double.
Integers are signed 32-bit values and thus can have a maximum value of 231 = (note that one bit is used for the sign).
You need to change the type of maxItemAmount to long.
you should go for 64 bit types ... i.e: long ...
do ...
public long maxItemAmount = 3000000000L;
A 32-bit signed integer has a range of -232 to 232-1, or − 2,147,483,648 to 2,147,483,647. If you want an integral value outside this range you need to use a 64-bit (long) variable. On the other hand, how likely is it that anyone will have over 2 billion distinct items or weapons? Perhaps, you want to rethink it and keep track of items and their quantities separately. You might also want to consider that changing to use a long may have unexpected consequences if parts of the code assume that it's a 32-bit value.
You can check out the max value of numbers with Integer.MAX_VALUE and Long.MAX_VALUE.
If a long is still not enough for your needs, you can check out the BigInteger class.
Instead of int you should use long. Here you can find more information about the precision of Java primitive data types.
Quoting from the link:
long: The long data type is a 64-bit signed two's complement integer. It has a minimum value of -9,223,372,036,854,775,808 and a maximum value of 9,223,372,036,854,775,807 (inclusive). Use this data type when you need a range of values wider than those provided by int.
As other people has sayed, you have to use another data type that support big numbers.
I recommend you using long. For example:
public long maxItemAmount = 3000000000L;
Notice the L at the end of the value. It tells the runtime that 3000000000 is a long value. Or use:
public long maxItemAmount = new Long("3000000000");
See more info on this page.
Also, someone commented using a BigInteger. It's like a String; don't have limit.
However, I recommend you to use it rarely. A long will probably suit your needs.
EDIT: Strictly speaking, BigIntegers and Strings have limit (see comments).

Java's L number (long) specification

It appears that when you type in a number in Java, the compiler automatically reads it as an integer, which is why when you type in (long) 6000000000 (not in integer's range) it will complain that 6000000000 is not an integer. To correct this, I had to specify 6000000000L. I just learned about this specification.
Are there other number specifications like for short, byte, float, double? It seems like these would be good to have because (I assume) if you could specify the number you're typing in is a short then java wouldn't have to cast it - that is an assumption, correct me if I'm wrong. I would normally search this question myself, but I don't know what this kind of number specification is even called.
There are specific suffixes for long (e.g. 39832L), float (e.g. 2.4f) and double (e.g. -7.832d).
If there is no suffix, and it is an integral type (e.g. 5623), it is assumed to be an int. If it is not an integral type (e.g. 3.14159), it is assumed to be a double.
In all other cases (byte, short, char), you need the cast as there is no specific suffix.
The Java spec allows both upper and lower case suffixes, but the upper case version for longs is preferred, as the upper case L is less easy to confuse with a numeral 1 than the lower case l.
See the JLS section 3.10 for the gory details (see the definition of IntegerTypeSuffix).
By default any integral primitive data type (byte, short, int, long) will be treated as int type by java compiler. For byte and short, as long as value assigned to them is in their range, there is no problem and no suffix required. If value assigned to byte and short exceeds their range, explicit type casting is required.
Ex:
byte b = 130; // CE: range is exceeding.
to overcome this perform type casting.
byte b = (byte)130; //valid, but chances of losing data is there.
In case of long data type, it can accept the integer value without any hassle. Suppose we assign like
long l = 2147483647; //which is max value of int
in this case no suffix like L/l is required. By default value 2147483647 is considered by java compiler is int type. Internal type casting is done by compiler and int is auto promoted to Long type.
long l = 2147483648; //CE: value is treated as int but out of range
Here we need to put suffix as L to treat the literal 2147483648 as long type by java compiler.
so finally
long l = 2147483648L;// works fine.
I hope you won't mind a slight tangent, but thought you may be interested to know that besides F (for float), D (for double), and L (for long), a proposal has been made to add suffixes for byte and short—Y and S respectively. This would eliminate to the need to cast to bytes when using literal syntax for byte (or short) arrays. Quoting the example from the proposal:
MAJOR BENEFIT: Why is the platform
better if the proposal is adopted?
cruddy code like
byte[] stuff = { 0x00, 0x7F, (byte)0x80, (byte)0xFF};
can be recoded as
byte[] ufum7 = { 0x00y, 0x7Fy, 0x80y, 0xFFy };
Joe Darcy is overseeing Project Coin for Java 7, and his blog has been an easy way to track these proposals.
These are literals and are described in section 3.10 of the Java language spec.
It seems like these would be good to
have because (I assume) if you could
specify the number you're typing in is
a short then java wouldn't have to
cast it
Since the parsing of literals happens at compile time, this is absolutely irrelevant in regard to performance. The only reason having short and byte suffixes would be nice is that it lead to more compact code.
Java has two types of data type :
Primitive Data-Type
Non-Primitive Data-Type
Certain data types require specifications like long, float, and double.
While assigning any of the above data types to any variable always remember to....
End the value with a "d" in double data type.
End the value with a "L" in long data type.
End the value with a "f" in float data type.
Example:
long number = 15000000000L;
float mysecondnum = 5.75f;
double mynumber = 19.99d;
More info:
The size of the long data type is 8 bytes.
The size of the float data type is 4 bytes.
The size of the double data type is 8 bytes.
The precision level of the long data type is up to 7-8 decimal points while the float data type is up to 15 decimal points.
Edit:
Along with this typecasting can be used to change the primitive data type from one to another.
Widening Casting(automatically): smaller type to a larger type size
Narrowing Casting(manually): larger type to a smaller size type
To understand why it is necessary to distinguish between int and long literals, consider:
long l = -1 >>> 1;
versus
int a = -1;
long l = a >>> 1;
Now as you would rightly expect, both code fragments give the same value to variable l. Without being able to distinguish int and long literals, what is the interpretation of -1 >>> 1?
-1L >>> 1 // ?
or
(int)-1 >>> 1 // ?
So even if the number is in the common range, we need to specify type. If the default changed with magnitude of the literal, then there would be a weird change in the interpretations of expressions just from changing the digits.
This does not occur for byte, short and char because they are always promoted before performing arithmetic and bitwise operations. Arguably their should be integer type suffixes for use in, say, array initialisation expressions, but there isn't. float uses suffix f and double d. Other literals have unambiguous types, with there being a special type for null.

Categories

Resources