Why use Double.doubleToLongBits() instead of casting? - java

EDIT:
I think my purpose was not understood, and so the negative votes and comments. I am NOT interested in knowing what bit of a floating point(double) means what, and if they match the same position in a long; this is totally irrelevant to me. My problem is the following: I want to use a single primitive array to store all my primitive values. If I choose a double[] as "storage", I need to be able to store longs in it too (I could also do it the other way around, but the problem would not go away, just be reversed). Since both are the same size, it should work, somehow. Using Double.doubleToRawLongBits(double) and Double.longBitsToDouble(long) allow me to do that. But what I wanted to know was: "Can I just put cast a long to an double and back, and always get the same long back?" If THAT is true, then it solves my problem, and I don't care if the bits gets moved around internally. So I wanted to test if I can safely safely do this. The output says all 64 bits could be accessed and modified individually, but possibly this is not sufficient to prove that no long bit gets lost/modified.
I just discovered, with a small test, that I can correctly "address" every bit in a double, just by casting to long and back. Here the test program (which succeeds, at least on Java 7 / Windows 7 64bit):
import static org.junit.Assert.assertTrue;
import org.junit.Test;
public class TestDoubleBits {
private static double set(final double d, final int bit, final boolean value) {
if (value) {
return ((long) d) | (1L << bit);
} else {
return ((long) d) & ~(1L << bit);
}
}
private static boolean get(final double d, final int bit) {
return (((long) d) & (1L << bit)) != 0;
}
#Test
public void testDoubleBits() {
final double value = Math.random();
for (int bit = 0; bit < 64; bit++) {
assertTrue((get(set(value, bit, false), bit) == false));
assertTrue((get(set(value, bit, true), bit) == true));
}
}
}
Assuming my test program correctly "proves" that every bit of a double can be accessed, just by casting to long and back, why do we have the following native methods:
Double.doubleToRawLongBits(double)
Double.longBitsToDouble(long)
Since native methods are usually slower (the content of the method might be faster, but the overhead of native call make it slower), is there any benefit to using those methods?

The bit pattern of a floating point number will NEVER (with ONE exception) remotely resemble the bit pattern of the corresponding integer value, if one exists.
I suggest you run the following program
public class Test
{
public static void main(String[] args) {
double d = 1.3;
long d1 = (long) d;
long d2 = (Double.doubleToLongBits(d));
System.out.printf("cast %016X bits %016X\n", d1, d2);
}
}
Then read What Every Computer Scientist Should Know About Floating-Point Arithmetic
(The exception is, of course, the value zero)
If you want to investigate further, there's a neat interactive floating point converter at CUNY that displays everything you'd ever want to know about any given number's float representations.

This is the test I should have used. It fails at 53, which (I assume) means that only the first 52 bits of a long could be stored in a double "safely" without using those native methods (this also precludes using any negative values).
public class TestDoubleBits {
public static void main(final String[] args) {
int failsAt = -1;
long value = 1;
for (int bit = 1; bit < 64; bit++) {
value = value | (1L << bit);
final double d = value;
final long l2 = (long) d;
if (value != l2) {
failsAt = bit;
break;
}
}
System.out.println("failsAt: " + failsAt);
value = value & ~(1L << failsAt);
System.out.println("Max value decimal: " + value);
System.out.println("Max value hex: " + Long.toHexString(value));
System.out.println("Max value binary: " + Long.toBinaryString(value));
}
}
The problem with my original test was that I tested the bits individually. By always setting the first bit to 1, I can find out when I start loosing data, because the least significant bit is the "first to go".

Related

Java double to int convertion changes sign of result

I tried to calculate a series of the N first fibonacci numbers using Binets Formula.
Every result i get is correct until F47 where the result is NEGATIVE.
This is my result : -1323752223
And heres the expected result : 2971215073
I really think the problem occures during the double to int conversion
Source Code:
import java.lang.Math;
class fibonacci{
public static int NthFibonacci(int n){
double fi = 1.61803398875;
int fb = (int)Math.round((Math.pow(fi,n) - Math.pow(1-fi,n))/Math.sqrt(5));
return fb;
}
public static void FibonacciSeries(Integer n){
for(int i = 0; i < n; i++){
System.out.println(NthFibonacci(i) + " ");
}
}
public static void main(String[] args) {
FibonacciSeries(50);
}
}
The real explanation for the behavior of the version in your question giving a negative number is a bit subtle.
At F47, this expression
(Math.pow(fi, n) - Math.pow(1 - fi, n)) / Math.sqrt(5)
will give you 2.971215073009069E9 ... which is close to the desired 2971215073.
The problem arises when you call Math.round(2.971215073009069E9). This returns a long - 2971215073L. But then you cast the result of the round call to an int, and it all goes pear-shaped.
Casting a long to an int will just lop off the top 32 bits ... and that results in a meaningless number.
If we modify fibonacci to return a long instead of an int, we get correct results up to F55. F56 and F57 are off by 1. F58 is off by 2.
What is happening now is that we are running into the problem that double (64-bit IEEE floating point) has only about 13.5 decimal digits of precision. The rounding error incurred in the computation of the intermediate floating point value for F56 larger that 0.5 ... so the rounded value is then incorrect.
The computed fibonacci numbers continue to get increasingly inaccurate until you get to F93, where the (modified) fibonacci method returns Long.MAX_VALUE.
To get correct values for very large Fibonacci numbers:
we need to use BigInteger to represent the numbers,
we need to do the computations using BigDecimal with sufficient precision, and (maybe)
we need to use a more accurate value for phi.
Or we need to use the recurrence relationship to compute the numbers.
The 2 take-aways from all of this are:
casting a long to an int is a lossy conversion, and
floating point arithmetic is inexact and ... tricky.
I think that the problem does not have something to do with the double conversion.
int can store numbers that can be represented by 32 bits. This means the highest number integer can represents is 2.147.483.647.
The F47 is breaking this limit and results in an bit-overflow, so it starts at -2.147.483.68 and adds the rest of your 2971215073 - 2147483647 to it. -1323752223 is the outcome.
Use a long (64bit) instead of an int and you should be good :)
2971215073 is too big to be represented as an int at all. The maximum value of an int -- Integer.MAX_VALUE -- is 2^31 - 1, or 2147483647.
Ok so i found a decent fix.
I used a Geometrical version of Binets rule which you can find here : Binets Geometrical Rule
I also used long instead of int so now I can accurately calculate up to F70. F71 is wrong by a digit and after that it just builds up.
New Source Code :
import java.lang.Math;
class fibonacci{
public static long NthFibonacci(int n){
double a = (1/Math.sqrt(5))*Math.pow(2, n);
double radians1 = Math.toRadians(36.0);
double radians2 = Math.toRadians(108.0);
double b = Math.pow(Math.cos(radians1), n) - Math.pow(Math.cos(radians2), n);
long fb = (long) Math.round(a*b);
return fb;
}
public static void FibonacciSeries(int n){
for(int i = 0; i < n; i++){
System.out.println( i + " : " + NthFibonacci(i));
}
}
public static void main(String[] args) {
FibonacciSeries(100);
}
}

Can we assume that x == (int)sqrt(x * x) for all positive integers?

In C++ the sqrt function operates only with double values.
If we use integers (unsigned long long) can we be sure that
x == sqrt(x * x)
for any positive x where x * x <= MAXIMUM_VALUE?
Is it depend on the machine architecture and compiler?
In Java, Math.sqrt(x) takes a double value. You stated that x is such that x * x is below Integer.MAX_VALUE. Every integer is perfectly representable in double - double in java is explicitly defined as an iEEE-754 style double with a 52-bit mantissa; therefore in java a double can perfectly represent all integral values between -2^52 and +2^52, which easily covers all int values (as that is defined as signed 32-bit on java), but it does not cover all long values. (Defined as signed 64-bit; 64 is more than 52, so no go).
Thus, x * x loses no precision when it ends up getting converted from int to double. Then, Math.sqrt() on this number will give a result that is also perfectly representable as a double (because it is x, and given that x*x fits in an int, x must also fit), and thus, yes, this will always work out for all x.
But, hey, why not give it a shot, right?
public static void main(String[] args) {
int i = 1;
while (true) {
if (i * i < 0) break;
int j = (int) Math.sqrt(i * i);
if (i != j) System.out.println("Oh dear! " + i + " -> " + j);
i++;
}
System.out.println("Done at " + i);
}
> Done at 46341
Thus proving it by exhaustively trying it all.
Turns out, none exist - any long value such that x * x still fits (thus, is <2^63-1) has the property that x == (long) Math.sqrt(x * x);. This is presumably because at x*x, the number fits perfectly in a long, even if not all integer numbers that are this large do. Proof:
long p = 2000000000L;
for (; true; p++) {
long pp = p * p;
if (pp < 0) break;
long q = (long) Math.sqrt(pp);
if (q != p) System.out.println("PROBLEM: " + p + " -> " + q);
}
System.out.println("Abort: " + p);
> Abort: 3037000500
Surely if any number exists that doesn't hold, there is at least one in this high end range. Starting from 0 takes very long.
But do we know that sqrt will always return an exact value for a perfect square, or might it be slightly inaccurate?
We should - it's java. Unlike C, almost everything is 'well defined', and a JVM cannot legally call itself one if it fails to produce the exact answer as specified. The leeway that the Math.sqrt docs provide is not sufficient for any answer other than precisely x to be a legal implementation, therefore, yes, this is a guarantee.
In theory the JVM has some very minor leeway with floating point numbers, which strictfp disables, but [A] that's more about using 80-bit registers to represent numbers instead of 64, which cannot possibly ruin this hypothesis, and [B] a while back a java tag question showed up to show strictfp having any effect on any hardware and any VM version and the only viable result was a non-reproducible thing from 15 years ago. I feel quite confident to state that this will always hold, regardless of hardware or VM version.
I think we can believe.
Type casting a floating point number to an integer is to take only integer part of it. I believe you may concern, for example, sqrt(4) yields a floating point number like 1.999...9 and it is type casted to 1. (Yielding 2.000...1 is fine because it will be type casted to 2.)
But the floating number 4 is like
(1 * 2-0 + 0 + 2-1 + ... + 0 * 2-23) * 22
according to Floating-point arithmetic.
Which means, it must not be smaller than 4 like 3.999...9. So also, sqrt of the number must not be smaller than
(1 * 2-0) * 2
So sqrt of a square of an integer will at least yield a floating point number greater than but close enough to the integer.
Just try it. Yes it works in Java, for non-negative numbers. Even works for long contrary to common opinion.
class Code {
public static void main(String[] args) throws Throwable {
for (long x=(long)Math.sqrt(Long.MAX_VALUE);; --x) {
if (!(x == (long)Math.sqrt(x * x))) {
System.err.println("Not true for: "+x);
break;
}
}
System.err.println("Done");
}
}
(The first number that doesn't work is 3037000500L which goes negative when squared.)
Even for longs, the range of testable values is around 2^31 or 2*10^9 so for something this trivial it is reasonable to check every single value. You can even brute force reasonable cryptographic functions for 32-bit values - something more people should realise. Won't work so well for the full 64 bits.
BigInteger - sqrt(since 9)
Use cases requiring tighter constraint over possibilities of overflow can use BigInteger
BigInteger should work for any practical use case.
Still for normal use case, this might not be efficient.
Constraints
BigInteger Limits
BigInteger must support values in the range -2^Integer.MAX_VALUE (exclusive) to +2^Integer.MAX_VALUE (exclusive) and may support values outside of that range. An ArithmeticException is thrown when a BigInteger constructor or method would generate a value outside of the supported range. The range of probable prime values is limited and may be less than the full supported positive range of BigInteger. The range must be at least 1 to 2500000000.
Implementation Note:
In the reference implementation, BigInteger constructors and operations throw ArithmeticException when the result is out of the supported range of -2^Integer.MAX_VALUE (exclusive) to +2^Integer.MAX_VALUE (exclusive).
Array size limit when initialized as byte array
String length limit when initialized as String
Definitely may not support 1/0
jshell> new BigInteger("1").divide(new BigInteger("0"))
| Exception java.lang.ArithmeticException: BigInteger divide by zero
| at MutableBigInteger.divideKnuth (MutableBigInteger.java:1178)
| at BigInteger.divideKnuth (BigInteger.java:2300)
| at BigInteger.divide (BigInteger.java:2281)
| at (#1:1)
An example code
import java.math.BigInteger;
import java.util.Arrays;
import java.util.List;
public class SquareAndSqrt {
static void valid() {
List<String> values = Arrays.asList("1", "9223372036854775807",
"92233720368547758079223372036854775807",
new BigInteger("2").pow(Short.MAX_VALUE - 1).toString());
for (String input : values) {
final BigInteger value = new BigInteger(input);
final BigInteger square = value.multiply(value);
final BigInteger sqrt = square.sqrt();
System.out.println("value: " + input + System.lineSeparator()
+ ", square: " + square + System.lineSeparator()
+ ", sqrt: " + sqrt + System.lineSeparator()
+ ", " + value.equals(sqrt));
System.out.println(System.lineSeparator().repeat(2)); // pre java 11 - System.out.println(new String(new char[2]).replace("\0", System.lineSeparator()));
}
}
static void mayBeInValid() {
try {
new BigInteger("2").pow(Integer.MAX_VALUE);
} catch (ArithmeticException e) {
System.out.print("value: 2^Integer.MAX_VALUE, Exception: " + e);
System.out.println(System.lineSeparator().repeat(2));
}
}
public static void main(String[] args) {
valid();
mayBeInValid();
}
}
in cmath library sqrt function always convert argument to double or float so the range of double or float much more than unsigned long long so it always give positive.
for reference you can use
https://learn.microsoft.com/en-us/cpp/standard-library/cmath?view=msvc-170,
https://learn.microsoft.com/en-us/cpp/c-language/type-float?view=msvc-170

How can I efficiently zero out the last 32 bits of a double in java?

How can I zero out the last 32 bits of a double, in java, as efficiently as possible?
Try this.
private static final long ZERO_OUT_LAST_32_BITS = 0xffffffff00000000L;
public static void main(String[] args) {
double number = 2.5;
long numberBits = Double.doubleToLongBits(number);
double result = Double.longBitsToDouble(numberBits & ZERO_OUT_LAST_32_BITS);
}
It zeroes out the last 32 bits of the binary representation of your double by using a binary AND operation.
However, make sure you know exactly what and why you are doing - I would at least expect an explaining comment next to code like this.
Convert to long and mask away the desired bits, convert back:
long l = Double.doubleToLongBits();
l &= 0xFFFFFFFF00000000L;
double truncated = Double.longBitsToDouble(l);
Although I'm not sure what you're trying to achive by that...

Java: efficiently store boolean[32]?

In Java, I would like to store (>10'000) arrays of boolean values (boolean[]) with length 32 to the disk and read them again later on for further computation and comparison.
Since a single array will have a length of 32, I wonder whether it makes sense to store it as an integer value to speed up the reading and writing (on a 32 bit machine). Would you suggest using BitSet and then convert to int? Or even forget about int and use bytes?
For binary storage, use int and a DataOutputStream (DataInputStream for reading).
I think boolean arrays are stored as byte or int arrays internally in Java, so you may want to consider avoiding the overhead and keeping the int encoding all the time, i.e. not use boolean[] at all.
Instead, have something like
public class BooleanArray32 {
private int values;
public boolean get(int pos) {
return (values & (1 << pos)) != 0;
}
public void set(int pos, boolean value) {
int mask = 1 << pos;
values = (values & ~mask) | (value ? mask : 0);
}
public void write(DataOutputStream dos) throws IOException {
dos.writeInt(values);
}
public void read(DataInputStream dis) throws IOException {
values = dis.readInt();
}
public int compare(BooleanArray32 b2) {
return countBits(b2.values & values);
}
// From http://graphics.stanford.edu/~seander/bithacks.html
// Disclaimer: I did not fully double check whether this works for Java's signed ints
public static int countBits(int v) {
v = v - ((v >>> 1) & 0x55555555); // reuse input as temporary
v = (v & 0x33333333) + ((v >>> 2) & 0x33333333); // temp
return ((v + (v >>> 4) & 0xF0F0F0F) * 0x1010101) >>> 24;
}
}
I am under the strong impression that any compression you are going to make to pack your boolean values will increase the read and write time. (my mistake, I was clearly missing my medication). You will rather gain in terms of storage involved.
BitSet is a sensible choice on your business logic side. It internally stores a long, which you could convert to an int. However, since BitSet is prude enough not to show you its privates, you need to get each bit index in sequence. This means that I guess there is no real advantage converting to an int rather than just using bytes directly.
The roll-your-own solution of Stefan Haustein (extended as necessary to mimic BitSet) is therefore preferable for your storage requirement, since you do not incur any unnecessary overhead.

Custom Data-type in Java

For an application I need to have an unsigned data-type with 24 bits.
Unfortunately such a data type is not available in Java. I’m planning to implement it as a new class.But I’m not sure about the performance of such an implementation.
Is it advisable to write my own class?
If it is advisable, is it possible to good performance?
Presumably, you mean implement it as a class which uses a larger data type and bounds checking, like this:
public class Unsigned24 {
private static final MAX_UNSIGNED24 = Math.pow(2, 24) - 1;
private static final MIN_UNSIGNED24 = 0;
private final int value;
public Unsigned24(int value) {
if (value > MAX_UNSIGNED24 || value < MIN_UNSIGNED24)
throw new IllegalArgumentException("value out of bounds: " + value);
this.value = value;
}
public int getValue() {
return value;
}
// ... other methods, such as equals(), comparison, addition, subtraction, etc.
}
This would work, but might not be worth the trouble. Also, it doesn't really take only 24 bits of memory, but rather 32 plus the overhead for an object.
It really depends on your goals. Why do you want a 24-bit integer.
Is it just because you have bounds-constraints on the values? If so, you might want to do something like the above.
Is it because you have a lot of them, and want to save memory? If so, you might want to build some class that abstracts an array of 24-bit integers, and internally saves them consecutively in a byte-array.
Is it because you are interfacing with some hardware or network interface that expects exactly 24 bits? In that case, you might want to look at the java.nio classes.
If you want to save space, you could use int for caluclation and map the least significant 3 bytes to a byte[] or just three bytes:
public static byte[] convert(int i) {
return new byte[]{ (i & 0xff0000) >> 16, (i & 0xff00) >> 8, (i & 0xff) };
}
public static int convert(byte[] b) {
if (b == null && b.length != 3)
throw new IllegalArgumentException();
return (b[2] << 16) | (b[1] << 8) | b;
}
(can't verify if it is bug free but at least it should give an idea)

Categories