We are often taught that floating-point numbers should not be compared for exact equality. However, the following function, which returns the Golden Ratio when passed any positive number, does in fact compare doubles for equality and to my surprise it seems to always work:
public static double f(double x) {
double y;
while ((y = 1 + 1 / x) != x)
x = (x + y) / 2;
return x;
}
#Test
void test() {
assertEquals((1 + sqrt(5)) / 2, f(1.0)); // Passes!
}
I thought that maybe it works for some input arguments but not others. But even if I use JQwik's property testing, it still works!
#Property
void test2(#ForAll #Positive double x) {
assertEquals((1 + sqrt(5)) / 2, f(x)); // Always passes!
}
Can anyone tell me why I never come across a situation where the two floating-point numbers are different by a very small amount?
You were just lucky, in general you don't get exact equality. Try this for example:
public static void main(String[] args) {
var s = 0.0;
for (int i = 0; i < 10; i++) {
s += 0.1;
}
System.out.println(s == 1.0);
}
In your concrete example one would have to do a careful analysis to prove that your iteration always converges to the floating point number closest to phi. If sqrt also returns the closest floating point number to the exact root we would get exact equality.
... and to my surprise it seems to always work:
Not always.
When I tried f(-1/1.6180339887498949), the x and y values oscillated between two floating point values that differed in the last few bits #Steve Summit. Thus an infinite loop.
x:-0.61803398874989490 y:-0.61803398874989468 // Decimal notation
x:-0x1.3c6ef372fe950p-1 y:-0x1.3c6ef372fe94ep-1 // Hex notation
x:-0.61803398874989479 y:-0.6180339887498949
x:-0x1.3c6ef372fe94fp-1 y:-0x1.3c6ef372fe950p-1
x:-0.61803398874989490 y:-0.61803398874989468
x:-0x1.3c6ef372fe950p-1 y:-0x1.3c6ef372fe94ep-1
f(some_starting_x) generally converges to render an x, such that 1 + 1 / x is x again and so meeting the stopping condition.
Better routines can prove that if x is reasonably close, the while loop will eventually get close to the desired answer, yet even then, an oscillation, as shown above is possible. Thus using an iteration limit or close enough test is needed. Usually the 2 oscillation values, when close, they are massaged (e.g. averaged) to form the best answer. If not close, the looping simply failed to find a stable answer.
Can anyone tell me why I never come across a situation where the two floating-point numbers are different by a very small amount?
Inadequate testing.
Morale of the story:
Do not rely on only floating point equality, except in select cases.
f() was not a select case and deserved additional stopping code.
Ref: Two x with math property: x = 1 + 1/x:
x1 = 1.6180339887498948482045868343656...
x2 = -0.61803398874989484820458683436564...
Note x1*x2 == -1. x1 is the Golden_ratio φ.
Related
I want to find whether a given number is a power of two in a mathematical way, not with a bitwise approach. Here is my code:
private static double logBaseTwo(final double x) {
return Math.log(x) / Math.log(2);
}
private static double roundToNearestHundredThousandth(final double x) {
return Math.round(x * 100000.0) / 100000.0;
}
private static boolean isInteger(final double x) {
return (int)(Math.ceil(x)) == (int)(Math.floor(x));
}
public static boolean isPowerOfTwo(final int n) {
return isInteger(roundToNearestHundredThousandth(logBaseTwo(n)));
}
It incorrectly returns true for certain numbers, such as 524287. Why is that?
Your code fails because you may need more precision than you allow to capture the difference between the logs of BIG_NUMBER and BIG_NUMBER+1
The bitwise way is really best, but if you really want to use only "mathy" operations, then the best you can do is probably:
public static boolean isPowerOfTwo(final int n) {
int exp = (int)Math.round(logBaseTwo(n));
int test = (int)Math.round(Math.pow(2.0,exp));
return test == n;
}
This solution does not require any super-fine precision, and will work fine for all positive ints.
This is truly horrifyingly bad code, and I have no idea what you are trying to do. You seem to be trying to check if the log base 2 of n is an integer. Instead I would write a loop:
while (n>1) {
m = (n/2) * 2
if (n!=m){
return false;
}
n /=2;
}
return true;
The solution seems more complicated than it should be. I don't get the 100000d parts - seems to potentially cause problems when converting to ceiling.
This is the simple solution that works for all cases:
public static boolean isPowerOfTwo(int n) {
return Math.ceil(Math.log(n)/Math.log(2)) == Math.floor(Math.log(n)/Math.log(2));
}
Originally I had a problem using Math.log in my computations. I switched to Math.log10 and the problem went away. Although mathematically, any logB of base B should work, the nature of floating point math can be unpredictable.
Try this.
public static boolean isPowerOfTwo(int n) {
return n > 0 && Integer.highestOneBit(n) == Integer.lowestOneBit(n);
}
If you prefer to use logs you can do it this way.
public static boolean isPowerOfTwo(int n) {
return n > 0 && (Math.log10(n)/Math.log10(2))%1 == 0;
}
doubles and floats have, respectively, 64-bit and 32-bit precision. That means they can hold at the very most 18446744073709551616 unique numbers. That's a lot of numbers, but not an infinite amount of them. At some point (in fact, that point occurs about at 2^52), the 'gap' between any 2 numbers which are part of the 18446744073709551616 representable ones becomes larger than 1.000. Similar rules apply to small numbers. Math.log does double based math.
Secondarily, ints are similarly limited. They can hold up to 4294967296 different numbers. For ints it's much simpler: Ints can hold from -2147483648 up to 2147483647. If you try to add 1 to 2147483647, you get -2147483648 (it silently wraps around). It's quite possible you're running into that with trying to convert such a large number (your double times 10000d) to an int first.
Note that ? true : false (as in the original version of the question) is literally completely useless. the thing to the left of the question mark must be a boolean, and booleans are already true or false, that's their nature.
See the other answers for simpler approaches to this problem. Although, of course, the simplest solution is to simply count bits in the number. If it's precisely 1 bit, it's a power of 2. If it's 0 bits, well, you tell me if you consider '0' a power of 2 :)
I'm trying to use the l2 normalization on a double vector with Java.
double[] vector = {0.00423823948, 0.00000000000823285934, 0.0000342523505342, 0.000040240234023423, 0, 0};
Now if i use the l2 normalization
for(double i : vector){
squareVectorSum += i * i;
}
normalizationFactor = Math.sqrt(squareVectorSum);
// System.out.println(squareVectorSum+" "+normalizationFactor);
for(int i = 0; i < vector.length; i++){
double normalizedFeature = vector[i] / normalizationFactor;
vector_result[i] = normalizedFeature;
}
My normalized vector is like this
Normalized vector (l2 normalization)
0.9999222784309146 1.9423676996312713E-9 0.008081112110203743 0.009493825603572155 0.0 0.0
Now if if make the squared sum of all the normalized-vector components I should get a sum that is is equal to one, instead my squared sum is
for(double i : vector_result){
sum += i*i;
}
Squared sum of the normalized-vector
1.0000000000000004
Why is my sum not equal to one?
Are there some problems in the code?
Or it's just because my numbers are too small and there is some approximation with doubles?
As indicated above, this is a common issue, one you're going to have to deal with if you're going to use floating point binary arithmetic. The problem mostly crops up when you want to compare two floating point binary numbers for equality. Since the operations applied to arrive at the values may not be identical, neither will their binary representations.
There are at least a couple strategies you can consider to deal with this situation. The first involves comparing the absolute difference between two floating point numbers, x and y rather than strict equality and comparing them to some small value ϵ>0. This would look something like
if (Math.abs(y-x) < epsilon) {
// Assume x == y
} else {
// Assume x != y
}
This works well when the possible values of x and y have a relatively tight bounding on their exponents. When this is not the case, value of x and y may be such that the difference always dominates the ϵ you choose (if the exponent is too large) or ϵ dominates the difference (such as when the possible exponents of x and y are small). To get around this, instead of comparing the absolute difference, you could instead compare the ratio of x and y to 1.0 and see whether that ratio has an absolute difference from 1.0 by more than ϵ. That would look like:
if (Math.abs(x/y-1.0) < epsilon) {
// Assume x == y
} else {
// Assume x != y
}
You will likely need to add another check to ensure y!=0 to avoid division by zero, but that's the general idea.
Other options include using a fixed point library for Java or a rational number library for Java. I have no recommendations for that, though.
Suppose we implement the following two methods to calculate the nth multiple of a real number x.
public static double multiply( double x, int n )
{
return x * n;
}
public static double iterativeAdd( double x, int n )
{
double a = 0.0;
for( int b = 0; b < n; b++ )
{
a += x;
}
return a;
}
Assume that n is a legal int and that both x and the exact mathematical product of n and x are no less in absolute value than Double.MIN_VALUE (unless both are 0.0) and no greater in absolute value than Double.MAX_VALUE. Here's what I'm wondering: In general, which is closer to the exact value of the product of x and n: the double returned by multiply( x, n ) or the double returned by iterativeAdd( x, n ) and how do you know?
According to my knowledge, the first method will produce more accurate result because in the second method after each addition probability that some of the digits will be truncated and rounded are more then a single multiplier operation as the result will be calculated once and then the digits will be truncated.
Generally, for every floating point operation you do, your epsilon increases. This happens because floating point numbers have a fixed size in memory, limiting their precision. Each operation is rounded to the nearest value that a float can represent. This rounding accumulates after a while.
Both numbers will get you very close to the answer, but if you run both methods on a large and varied set of numbers, you will see that on average iterativeAdd() has a greater distance from the actual value.
Additionally, multiply() will be significantly faster on any machine, so there's no benefit to ever using iterativeAdd().
Both will return approximately the same value, however there is greater chance that the iterativeAdd() will return more inapproximate value, but the difference will be negligible.
Any single float operation results in some precision loss however small.
In multiply() you make use of the float operation only once but in iterativeAdd() you use it n times.
In general we should avoid using any function like iterativeAdd() as it is will take up a lot of processor time with n floating point operations.
I was interviewed yesterday and this question arise:
public class Main {
public static void main(String[] args) {
// Code fragment must prints true if the double variables x and y are both
// strictly between 0 and 1 and false otherwise.
// Assuming args will be always correct (double) input,
// Where's the safety bug?
double x,y;
x = Double.parseDouble(args[0]);
y = Double.parseDouble(args[1]);
System.out.println( (0 < x && x < 1) && (0 < y && y < 1)? true : false );
}
}
I wrote there were no bug anywhere, I mean, code works. Back at home, tried and indeed it works. But although I did get the job, this question was my only bad one, and I can't get it out of my head (it seams fair straight simple). I believe I don't even understand what a safety bug is so, my question then is:
What's a safety bug and does this code indeed have one?
UPDATE:
After response I put some related resources:
Eric Lippert's Why does JScript have rounding errors?
Judging from the comment in the source:
Assuming args will be always correct (double) input, Where's the safety bug?
There exists a case in which the program will deliver a wrong output, and there seems to be no dubious except the expression itself:
(0 < x && x < 1) && (0 < y && y < 1)
Although I haven't tested it, there may be a problem when this expression is confronted with one of the edge cases for either x or y: NaN, +/- infinity and maybe even -0.0.
Also there exist definitively valid inputs which may violate the logical expectation of the user due to the limited precision with which number are represented in a double (e.g. x = 1E-400 is greater than 0, but parses as 0, so the expression delivers false although the user would expect true).
I would go with type safety and uncaught exception if the input somewhat happens to not be double. Then the code just throws an exception.
You can set x to 0, and you can enter 0 for y. But the values must be between.
You better use strictfp.
You better use 0d instead of 0.
I am working on an exercise in Java. I am supposed to use / and % to extract digits from a number. The number would be something like 1349.9431. The output would be something like:
1349.9431
1349.943
1349.94
1349.9
I know this is a strange way to do but the lab exercise requires it.
Let's think about what you know. Let say you have the number 12345. What's the result of dividing 12345 by 10? What's the result of taking 12345 mod 10?
Now think about 0.12345. What's the result of multiplying that by 10? What's the result of that mod 10?
The key is in those answers.
if x is your number you should be able to do something like x - x%0.1 to get the 1349.9, then x - x%.0.01 to get 1349.94 and so on. I'm not sure though, doing mod on floats is kind of unusual to begin with, but I think it should work that way.
x - x%10 would definetly get you 1340 and x - x%100 = 1300 for sure.
Well the work will be done in background anyway, so why even bother, just print it.
float dv = 1349.9431f;
System.out.printf("%8.3f %8.2f %8.1f", dv, dv, dv);
Alternatively this could be archived with:
float dv = 1349.9431f;
System.out.println(String.format("%8.3f %8.2f %8.1f", dv, dv, dv));
This is a homework question so doing something the way you would actually do in the real world (i.e. using the format method of String as Margus did) isn't allowed. I can see three constraints on any answer given what is contained in your question (if these aren't actually constraints you need to reword your question!)
Must accept a float as an input (and, if possible, use floats exclusively)
Must use the remainder (%) and division (/) operator
Input float must be able to have four digits before and after the decimal point and still give the correct answer.
Constraint 1. is a total pain because you're going to hit your head on floating point precision quite easily if you have to use a number with four digits before and after the decimal point.
float inputNumber = 1234.5678f;
System.out.println(inputNumber % 0.1);
prints "0.06774902343743147"
casting the input float to a double casuses more headaches:
float one = 1234.5678f;
double two = (double) one;
prints "1234.5677490234375" (note: rounding off the answer will get you 1234.5677, which != 1234.5678)
To be honest, this had me really stumped, I spent way too much time trying to figure out how to get around the precision issue. I couldn't find a way to make this program work for 1234.5678f, but it does work for the asker's value of 1349.9431f.
float input = 1349.9431f;
float inputCopy = input;
int numberOfDecimalPoints = 0;
while(inputCopy != (int) inputCopy)
{
inputCopy = inputCopy * 10;
numberOfDecimalPoints++;
}
double inputDouble = (double) input;
double test = inputDouble * Math.pow(10, numberOfDecimalPoints);
long inputLong = Math.round(test);
System.out.println(input);
for(int divisor = 10; divisor < Math.pow(10, numberOfDecimalPoints); divisor = divisor * 10)
{
long printMe = inputLong - (inputLong % divisor);
System.out.println(printMe / Math.pow(10, numberOfDecimalPoints));
}
Of my three constraints, I've satisfied 1 (kind of), 2 but not 3 as it is highly value-dependent.
I'm very interested to see what other SO people can come up with. If the asker has parsed the instructions correctly, it's a very poor exercise, IMO.