I'm trying to convert double precision number to decimal .
for example the number 22 in double precision and as bytes are :
[0] 0
[1] 0
[2] 0
[3] 0
[4] 0
[5] 0
[6] 54
[7] 64
now I try to convert these values again to 22 :
ByteBuffer buffer = ByteBuffer.wrap(data);
long l = buffer.getLong();
long b = Double.doubleToLongBits(l);
but the result is something totally wrong :4.6688606E18
what's this number ? please help , I'm totally confused!
according to IEEE Standard 754 for double precision:
Any value stored as a double requires 64 bits, formatted as shown in the table below:
63
Sign (0 = positive, 1 = negative)
62 to 52
Exponent, biased by 1023
51 to 0
Fraction f of the number 1.f
now how should I convert double precision to numbers to get 22 again ? all of these answers are wrong
I'm not sure exactly what sort of conversion you're trying to do (when you say "convert to decimal", what is your desired output format/class?)
However, my first thought reading the title was that a BigDecimal would be a valid representation. So the first approach would be to do something like the following:
double d = ...; // your input number
BigDecimal b = new BigDecimal(d);
That said, if you want to convert to decimal then it's presumably because there are floating ponit/rounding issues with the value of d, which will still be present in the BigDecimal representation as it's being constructed based on d.
The best approach to get around this is to use BigDecimals from the get-go, using their String constructor - so there won't be any instances of floating-point rounding. If this isn't an option for whatever reason, you can convert the double to a string in such a way that it will account for many floating point rounding issues:
String strRep = Double.toString(d);
BigDecimal b = new BigDecimal(strRep);
You can write simple test (with JUnit):
double initial = 22.0;
long bits = Double.doubleToLongBits(initial);
double converted = Double.longBitsToDouble(bits);
assertEquals(Double.valueOf(initial), Double.valueOf(converted));
If this works - check you have correct byte representation for 22 (correct representation will be at bits variable).
Related
I'm trying to understand the scale for a BigDecimal but it acts weird and I can't understand why. Here's a couple of examples:
Double d = new Double(1000000d);
int scale = new BigDecimal(d.toString()).scale();
The scale in this example will be 1 which is correct to me.
The result of d.toString() is "1000000.0".
Double d = new Double(10000000d);
int scale = new BigDecimal(d.toString)).scale();
The scale in this example will be -6. Can anyone explain why?
The result of d.toString() is "1.0E7".
I thought the number of digits caused this but if I go:
Double d = new Double(11111111d);
int scale = new BigDecimal(d.toString()).scale();
Expected a scale of -8 but suddenly it's 0.
The result of d.toString() is "1.1111111E7".
These different scales make no sense to me after reading the Javadoc of scale():
Returns the scale of this BigDecimal. If zero or positive, the scale is the number of digits to the right of the decimal point. If negative, the unscaled value of the number is multiplied by ten to the power of the negation of the scale. For example, a scale of -3 means the unscaled value is multiplied by 1000.
I'd very much appreciate an explanation how BigDecimal behaves when the numbers are large.
Thanks in advance!
The scale you got is the number of decimals with some significance:
1000000d -> 1000000.0 -> 0: the numbers at the right of the dot have no significance, the result is 0;
10000000d -> 1.0E7 -> -6: the numbers at the right of the dot have significance, as if you denormalize the power by ten you get the 6 zeros;
11111111d -> 1.1111111E7 -> 0: all the numbers at the right of the dot have significance, denormalizing the power by ten you get more information, so you "can't" normalize the number if you want to keep this information. This way (the number denormalized), you have 0 numbers at the right of the dot.
EDIT
As commented, the first line is wrong, it must be 1000000d -> 1000000.0 -> 1. The reason is that the numbers with exponential have a different behavior (when obtaining the scale) that the formatted numbers.
The value of 1 is due that BigDecimal counts the numbers in the right side of the dot (which in this case is one, a single 0), subtract the numbers to drop (in this case there is one, the single 0) and add the math precision (by default is one) -> result = 1.
You are seeing the behavior your report because you are calling toString() on the decimal provided, which in for some of your examples represents in exponential notation, which is then preserved by BigDecimal when it chooses the scale.
If you provide the the double directly to the BigDecimal constructor you consistently get 0.
new Double(1000000d).toString() //1.0E7
Double d = new Double(1000000d);
int scale = new BigDecimal(d).scale(); //0
Double d = new Double(10000000d);
int scale = new BigDecimal(d).scale(); //0
Double d = new Double(11111111d);
int scale = new BigDecimal(d).scale(); //0
Update:
scale is is not a useful attribute on its own. It must be considered in conjunction with unscaledValue. The represented number is unscaledValue × 10 ^ -scale.
That is,
BigDecimal d = new BigDecimal(1000000d)
BigDecimal e = d.setScale(2)
int dScale = d.scale() //0
int dUnscaled = d.unscaledValue() //1000000
int eScale = e.scale() //2
int eUnscaled = e.unscaledValue() //100000000
Both d and e are a representation of 1000000. However, e preserves there are 2 trailing zeros (zeros after the decimal point).
d.toString() //1000000
e.toString() //1000000.00
This question already has answers here:
How to resolve a Java Rounding Double issue [duplicate]
(13 answers)
Closed 9 years ago.
why is the Double.parseDouble making 9999999999999999 to 10000000000000000 ?
For Example :
Double d =Double.parseDouble("9999999999999999");
String b= new DecimalFormat("#.##").format(d);
System.out.println(b);
IS Printing
10000000000000000
instead it has to show 9999999999999999 or 9999999999999999.00
Any sort of help is greatly appreciated.
The number 9999999999999999 is just above the precision limit of double-precision floating-point. In other words, the 53-bit mantissa is not able to hold 9999999999999999.
So the result is that it is rounded to the nearest double-precision value - which is 10000000000000000.
9999999999999999 = 0x2386f26fc0ffff // 54 significant bits needed
10000000000000000 = 0x2386f26fc10000 // 38 significant bits needed
double only has 15/16 digits of accuracy and when you give it a number it can't represent (which is most of the time, even 0.1 is not accurate) it takes the closest representable number.
If you want to represent 9999999999999999 exactly, you need to use BigDecimal.
BigDecimal bd = new BigDecimal("9999999999999999");
System.out.println(new DecimalFormat("#.##").format(bd));
prints
9999999999999999
Very few real world problems need this accuracy because you can't measure anything this accurately anyway. i.e. to an error of 1 part per quintillion.
You can find the largest representable integer with
// search all the powers of 2 until (x + 1) - x != 1
for (long l = 1; l > 0; l <<= 1) {
double d0 = l;
double d1 = l + 1;
if (d1 - d0 != 1) {
System.out.println("Cannot represent " + (l + 1) + " was " + d1);
break;
}
}
prints
Cannot represent 9007199254740993 was 9.007199254740992E15
The largest representable integer is 9007199254740992 as it needs one less bit (as its even)
9999999999999999 requires 54 bits of mantissa in order to be represented exactly, and double only has 52. The number is therefore rounded to the nearest number that can be represented using a 52-bit mantissa. This number happens to be 10000000000000000.
The reason 10000000000000000 requires fewer bits is that its binary representation ends in a lot of zeroes, and those zeroes can get represented by increasing the (binary) exponent.
For detailed explanation of a similar problem, see Why is (long)9223372036854665200d giving me 9223372036854665216?
This question already has answers here:
How to nicely format floating numbers to string without unnecessary decimal 0's
(29 answers)
Closed 9 years ago.
I know how to format a double to keep only the available decimal places (DP), up to a certain number of DPs. This example keeps up to 4 DPs.
double d = 1.0;
DecimalFormat df = new DecimalFormat("#.####");
System.out.print(df.format(d)); // returns "1"
double d = 1.23;
DecimalFormat df = new DecimalFormat("#.####");
System.out.print(df.format(d)); // returns "1.23"
double d = 1.2345678;
DecimalFormat df = new DecimalFormat("#.####");
System.out.print(df.format(d)); // returns "1.2346", rounding off: bad!
Now I want whole numbers e.g. 1.0 to return "1" without the unnecessary .0, and the # format character does provide that functionality. But how do I make sure that the number never gets rounded off? Is there any other way other than an arbitrarily long chain of # such as "#.###########################################"?
Or should I just use the default conversion of double to string, and truncate the ".0" if it appears at the end:
String s = "" + d;
if(s.substring(s.length()-2).equals(".0")) {
s=s.substring(0, s.length()-2);
}
Both ways seems terribly clumsy.
I use the following
double d =
String s = (long) d == d ? "" + (long) d : "" + d;
if you need Double instead for double. (Personally I would avoid using the wrapper if you can)
Double d =
String s = d.longValue() == d ? "" + d.longValue() : "" + d;
By default the rounding mode is Up for DecimalFormat. You can set different rounding format as per your requiremnet using setRoundingMode() method
Sample Code to set Rounding mode
double d = 1.2345678;
DecimalFormat df = new DecimalFormat("#.####");
df.setRoundingMode(RoundingMode.DOWN);
System.out.print(df.format(d));//result 1.2345 because of rounding down
You could use Double.doubleToLongBits() and extract the exponent and mantissa. From api doc:
Bit 63 (the bit that is selected by the mask 0x8000000000000000L)
represents the sign of the floating-point number. Bits 62-52 (the bits
that are selected by the mask 0x7ff0000000000000L) represent the
exponent. Bits 51-0 (the bits that are selected by the mask
0x000fffffffffffffL) represent the significand (sometimes called the
mantissa) of the floating-point number.
The exponent can be used to determine the number of significant digits, but you will always have to round at some point as some binary doulbe values will be endless in decimal.
For a binary representation you could simply use the mantissa and put the decimal dot at the right position (padding with zeros if necessary.
I have to convert a floating point to 32-bit fixed point in Java .
Not able to understand what is a 32-bit fixed point ?
Can any body help with algorithm ?
A fixed-point number is a representation of a real number using a certain number of bits of a type for the integer part, and the remaining bits of the type for the fractional part. The number of bits representing each part is fixed (hence the name, fixed-point). An integer type is usually used to store fixed-point values.
Fixed-point numbers are usually used in systems which don't have floating point support, or need more speed than floating point can provide. Fixed-point calculations can be performed using the CPU's integer instructions.
A 32-bit fixed-point number would be stored in an 32-bit type such as int.
Normally each bit in an (unsigned in this case) integer type would represent an integer value 2^n as follows:
1 0 1 1 0 0 1 0 = 2^7 + 2^5 + 2^4 + 2^1 = 178
2^7 2^6 2^5 2^4 2^3 2^2 2^1 2^0
But if the type is used to store a fixed-point value, the bits are interpreted slightly differently:
1 0 1 1 0 0 1 0 = 2^3 + 2^1 + 2^0 + 2^-3 = 11.125
2^3 2^2 2^1 2^0 2^-1 2^-2 2^-3 2^-4
The fixed point number in the example above is called a 4.4 fixed-point number, since there are 4 bits in the integer part and 4 bits in the fractional part of the number. In a 32 bit type the fixed-point value would typically be in 16.16 format, but also could be 24.8, 28.4 or any other combination.
Converting from a floating-point value to a fixed-point value involves the following steps:
Multiply the float by 2^(number of fractional bits for the type), eg. 2^8 for 24.8
Round the result (just add 0.5) if necessary, and floor it (or cast to an integer type) leaving an integer value.
Assign this value into the fixed-point type.
Obviously you can lose some precision in the fractional part of the number. If the precision of the fractional part is important, the choice of fixed-point format can reflect this - eg. use 16.16 or 8.24 instead of 24.8.
Negative values can also be handled in the same way if your fixed-point number needs to be signed.
If my Java were stronger I'd attempt some code, but I usually write such things in C, so I won't attempt a Java version. Besides, stacker's version looks good to me, with the minor exception that it doesn't offer the possibility of rounding. He even shows you how to perform a multiplication (the shift is important!)
A very simple example for converting to fixed point, it shows how to convert and multiplies PI by2. The resulting is converted back to double to demonstrate that the mantissa wasn't lost during calculation with integers.
You could expand that easily with sin() and cos() lookup tables etc.
I would recommend if you plan to use fixed point to look for a java fixed point library.
public class Fix {
public static final int FIXED_POINT = 16;
public static final int ONE = 1 << FIXED_POINT;
public static int mul(int a, int b) {
return (int) ((long) a * (long) b >> FIXED_POINT);
}
public static int toFix( double val ) {
return (int) (val * ONE);
}
public static int intVal( int fix ) {
return fix >> FIXED_POINT;
}
public static double doubleVal( int fix ) {
return ((double) fix) / ONE;
}
public static void main(String[] args) {
int f1 = toFix( Math.PI );
int f2 = toFix( 2 );
int result = mul( f1, f2 );
System.out.println( "f1:" + f1 + "," + intVal( f1 ) );
System.out.println( "f2:" + f2 + "," + intVal( f2 ) );
System.out.println( "r:" + result +"," + intVal( result));
System.out.println( "double: " + doubleVal( result ));
}
}
OUTPUT
f1:205887,3
f2:131072,2
r:411774,6
double: 6.283172607421875
A fixed-point type is one that has a fixed number of decimal/binary places after the radix point. Or more generally, a type that can store multiples of 1/N for some positive integer N.
Internally, fixed-point numbers are stored as the value multiplied by the scaling factor. For example, 123.45 with a scaling factor of 100 is stored as if it were the integer 12345.
To convert the internal value of a fixed-point number to floating point, simply divide by the scaling factor. To convert the other way, multiply by the scaling factor and round to the nearest integer.
The definition of 32-bit fixed point could vary. The general idea of fixed point is that you have some fixed number of bits before and another fixed number of bits after the decimal point (or binary point). For a 32-bit one, the most common split is probably even (16 before, 16 after), but depending on the purpose there's no guarantee of that.
As far as the conversion goes, again it's open to some variation -- for example, if the input number is outside the range of the target, you might want to do any number of different things (e.g., in some cases wraparound could make sense, but in others saturation might be preferred).
I need to convert 0.5 in base 10 to base 2 (0.1).
I have tried using
Double.doubleToRawLongBits(0.5)
and it returns 4602678819172646912 which I guess is in hex, but it does not make sense to me.
No. 4602678819172646912 is in dec, hex is 0x3fe0000000000000. To dismantle that:
3 | F | E | 0 ...
0 0 1 1 1 1 1 1 1 1 1 0 0 ...
s| exponent | mantissa
s is the sign bit, exponent is the exponent shifted by 2^9 (hence this exponent means -1), mantissa is the xxx part of the number 1.xxx (1. is implied). Therefore, this number is 1.000...*2^-1, which is 0.5.
Note that this describes the "normal" numbers only, so no zeros, denormals, NaNs or infinities
Multiply you number by 2^n, convert to an BigInteger, convert to binary String, add a decimal point at position n (from right to left).
Example (quick & ++dirty):
private static String convert(double number) {
int n = 10; // constant?
BigDecimal bd = new BigDecimal(number);
BigDecimal mult = new BigDecimal(2).pow(n);
bd = bd.multiply(mult);
BigInteger bi = bd.toBigInteger();
StringBuilder str = new StringBuilder(bi.toString(2));
while (str.length() < n+1) { // +1 for leading zero
str.insert(0, "0");
}
str.insert(str.length()-n, ".");
return str.toString();
}
This is decimal for 0x3FE0_0000_0000_0000. The mantissa is the list of zeros after 3FE (which codes sign and exponent). This is what you are looking for, given that 0.1 before the zeros is implicit.
Do you want to convert the decimal string to floating-point binary or to a binary string? If the former, just use valueOf(); if the latter, use valueOf() followed by toString() or printf().
0.1 is NOT a binary representation of 0.5
Java will represent 0.5 using IEEE 754, as specified on the Java Language Specification. BigInteger.valueOf(Double.doubleToRawLongBits(0.5)).toByteArray() will give you a byte per byte representation of 0.5 as Java does internally.