Math.pow(10,6) = 999999.999999 on Doogee DG800 Android phone - java

I know that Math.pow(10,6) performs the computation using doubles which means the precision is not absolute. The current release of Google Authenticator uses following code to compute codes:
int codeLength = 6;
....
int code = truncatedHash % (int) Math.pow(10, codeLength);
Unfortunately at least two Android phones (see google-authenticator issue 396) compute 999999.9999999, which results in incorrect (not working) authentication codes.
The fix is known and it uses a table of integer dividers as the count is limited to 10 possible values (see the fix referenced from the issue).
And here is the question: Is it the application programmer's fault or the library programmer's fault? Should the application programmer expect the correct result (1000000) or must the limited precision be taken into account?

Yes, it's a bug in the library, and it should be reported.
Oracle's Javadoc for Math.pow() says, "If both arguments are integers, then the result is exactly equal to the mathematical result of raising the first argument to the power of the second argument if that result can in fact be represented exactly as a double value."
The word "integer" has special meaning here. A double x is an integer if floor(x) == x.
10.0 is an "integer" by that definition, and so is 6.0, and every integer less than 2^52 can be represented exactly as a double value, so Math.pow(10.0, 6.0) should be exactly equal to 1000000.0.

its the "library programmers fault", incorrectly using math-functions is a beginners' mistake and can never be compensated for in wrapping applications - its basic knowledge that operations on floating-points types never yield exact results, relying on these without using proper delta-comparisons with sensible values INTERNALLY is ... very bad.
I recommend switching the library - if it has flaws like this you can be quite sure that there are also a few more, maybe even security-related bugs.

Related

ULP calculation floating-point

I'm currently writing a "new language" at school, and I have to implement a Math class.
One of the specifications is to implement ulp method, like Math.ulp() in Java. We are working on float types.
I found many interesting sources, but I'm still not able to calculate ulp of a float..
AFAIK, if
then
But, how can I get this normalized form for a float without any lib ?
And how to get parameters e & n+1 ?
Thank you for your help,
Best regards,
I'm not sure Java has the possibility of aliasing to get the bit pattern of the floating point number (there is a close enough alternative, as the second part of the answer shows), but if it does, then e is the bits 23 through 30 (31 is sign) minus some constant (as in the wikipedia description of the format, it's 127 unless the number is subnormal) while n is fixed (in this case it's 23 bits, or 24 if it includes the implicit 1)
It's recommended you use a lib that does this job for you properly.
Another option I've been notified in the comments of (rather indirectly) implies converting the float bits to int. I will write a snippet of code directly. I'm not fully versed in Java (the code may not work immediately due to lacking package/class specifiers (floatToIntBits as well as intToFloatBits are static methods of the class java.lang.Float). This is different from the above suggestion since it's a bit unorthodox but it has better performance than the code you suggested in the question itself.
float ulp(float x) {
int repr;
float next;
if (Float.isNaN(x)) return Float.NaN; //special handling, to be safe
repr = Float.floatToIntBits(x);
x++; //will work correctly independently of sign
next = Float.intBitsToFloat(repr)
return next-x;
}

Java: How to replace common trigonometric values

I was wondering how to replace common trigonometric values in an expression. To put this into more context, I am making a calculator that needs to be able to evaluate user inputs such as "sin(Math.PI)", or "sin(6 * math.PI/2)". The problem is that floating point values aren't accurate and when I input sin(Math.PI), the calculator ends up with:
1.2245457991473532E-16
But I want it to return 0. I know I could try replacing in the expression all sin(Math.PI) and other common expressions with 0, 1, etc., except I have to check all multiples of Math.PI/2. Can any of you give me some guidance on how to return the user the proper values?
You're running into the problem that it's not quite possible to express a number like pi in a fixed number of bits, so with the available machine precision the computation gives you a small but non-zero number. Math.PI in any case is only an approximation of PI, which is an irrational number. To clean up your answer for display purposes, one possibility is to use rounding. You could instead try adding +1 and -1 to it which may well round the answer to zero.
This question here may help you further:
Java Strange Behavior with Sin and ToRadians
Your problem is that 1.2245457991473532E-16 is in fact zero for many purposes. What about simply rounding the result yielded by sin? With enough rounding, you may achieve what you want and even get 0.5, -0.5 and other important sin values relatively easily.
If you really want to replace those functions as your title suggests, then you can't do that in Java. Your best bet would be to create an SPI specification for common functions that could either fall back to the standard Java implementation or use your own implementation, which replaces the Java one.
Then users of your solution would need to retrieve one of the implementations using dependency injection of explicit references to a factory method.

How to get the smallest next or previous possible double value supported by the architecture?

Lets say I have a double variable d. Is there a way to get the next or previous value that is supported by the CPU architecture.
As a trivial example, if the value was 10.1245125 and the precision of the architecture was fixed to 7 decimal places, then the next value would be 10.1245126 and the previous value would be 10.1245124.
Obviously on floating-point architectures this is not that simple. How would I be able to achieve this (in Java)?
Actually, an IEEE 754 floating-point architecture makes this easy: thanks to the standard, the function is called nextafter in nearly all languages that support it, and this uniformity allowed me to write an answer to your question with very little familiarity with Java:
The java.lang.Math.nextAfter(double start, double direction) returns the floating-point number adjacent to the first argument in the direction of the second argument.
Remember that -infinity and +infinity are floating-point values, and these values are convenient to give the direction (second argument). Do not make the common mistake of writing something like Math.nextAfter(x, x+1), which only works as long as 1 is greater than the ULP of x.
Anyone who writes the above probably means instead Math.nextAfter(x, Double.POSITIVE_INFINITY), which saves an addition and works for all values of x.
Math.nextUp and Math.nextDown can be used to get the next/previous element, which are equivalent to the proposed methods in the accepted answer, but more concise.
(this info has been originally provided as a comment by #BjörnZurmaar)

Why is Math.floor() used instead of integer division in BER Codec

I am looking at the SNMPBEECodec which can be seen at this location
In particular I am looking at the function encodeLength()
A snippet I am interested in
int numBytes = 0;
int temp = length;
while (temp > 0)
{
++numBytes;
temp = (int)Math.floor(temp / 256);
}
(from the Drexel SNMP library).
I would like to know why Math.floor() is used instead of just a simple integer division like temp/256. It seems the simple integer division would give the same result. Or is there a technical difference?
To answer the technical part of your question:
Using math.floor() is superfluous: temp / 256 is an integer (by Java's rules for integer arithmetic), and using Math.floor() on an integer is pointless. You could simply use temp / 256.
Why the author did this is impossible to answer without reading their mind. The author might simply have been confused about the behaviour of division in Java, and decided to "play it safe" - but that is just speculation.
Well, unfortunately the author can no longer read his mind either - it's been about 12 years since I wrote this, so I forget the reason I didn't just use integer division. Some thoughts: I use integer division elsewhere assuming the usual behavior, so it wouldn't likely have been basic confusion on the rules for integer division in Java; it's possible (though unlikely) that I was at some point using a non-integral data type for the argument, and didn't get rid of the superfluous floor() when I changed; or perhaps (more likely) I was at some point attempting to round up rather than down while developing the algorithm, using ceil() as a cheap (= fewer characters) way to do this, and just reflexively switched to floor() when I changed.
So unfortunately the real reason is lost in the mists of time... but I agree, the floor() is superfluous. I should really post the code on Github or the like so folks can improve and evolve it.
\
Jon

Why does Math.round return a long but Math.floor return a double?

Why the inconsistency?
There is no inconsistency: the methods are simply designed to follow different specifications.
long round(double a)
Returns the closest long to the argument.
double floor(double a)
Returns the largest (closest to positive infinity) double value that is less than or equal to the argument and is equal to a mathematical integer.
Compare with double ceil(double a)
double rint(double a)
Returns the double value that is closest in value to the argument and is equal to a mathematical integer
So by design round rounds to a long and rint rounds to a double. This has always been the case since JDK 1.0.
Other methods were added in JDK 1.2 (e.g. toRadians, toDegrees); others were added in 1.5 (e.g. log10, ulp, signum, etc), and yet some more were added in 1.6 (e.g. copySign, getExponent, nextUp, etc) (look for the Since: metadata in the documentation); but round and rint have always had each other the way they are now since the beginning.
Arguably, perhaps instead of long round and double rint, it'd be more "consistent" to name them double round and long rlong, but this is argumentative. That said, if you insist on categorically calling this an "inconsistency", then the reason may be as unsatisfying as "because it's inevitable".
Here's a quote from Effective Java 2nd Edition, Item 40: Design method signatures carefully:
When in doubt, look to the Java library APIs for guidance. While there are plenty of inconsistencies -- inevitable, given the size and scope of these libraries -- there are also fair amount of consensus.
Distantly related questions
Why does int num = Integer.getInteger("123") throw NullPointerException?
Most awkward/misleading method in Java Base API ?
Most Astonishing Violation of the Principle of Least Astonishment
floor would have been chosen to match the standard c routine in math.h (rint, mentioned in another answer, is also present in that library, and returns a double, as in java).
but round was not a standard function in c at that time (it's not mentioned in C89 - c identifiers and standards; c99 does define round and it returns a double, as you would expect). it's normal for language designers to "borrow" ideas, so maybe it comes from some other language? fortran 77 doesn't have a function of that name and i am not sure what else would have been used back then as a reference. perhaps vb - that does have Round but, unfortunately for this theory, it returns a double (php too). interestingly, perl deliberately avoids defining round.
[update: hmmm. looks like smalltalk returns integers. i don't know enough about smalltalk to know if that is correct and/or general, and the method is called rounded, but it might be the source. smalltalk did influence java in some ways (although more conceptually than in details).]
if it's not smalltalk, then we're left with the hypothesis that someone simply chose poorly (given the implicit conversions possible in java it seems to me that returning a double would have been more useful, since then it can be used both while converting types and when doing floating point calculations).
in other words: functions common to java and c tend to be consistent with the c library standard at the time; the rest seem to be arbitrary, but this particular wrinkle may have come from smalltalk.
I agree, that it is odd that Math.round(double) returns long. If large double values are cast to long (which is what Math.round implicitly does), Long.MAX_VALUE is returned. An alternative is using Math.rint() in order to avoid that. However, Math.rint() has a somewhat strange rounding behavior: ties are settled by rounding to the even integer, i.e. 4.5 is rounded down to 4.0 but 5.5 is rounded up to 6.0). Another alternative is to use Math.floor(x+0.5). But be aware that 1.5 is rounded to 2 while -1.5 is rounded to -1, not -2. Yet another alternative is to use Math.round, but only if the number is in the range between Long.MIN_VALUE and Long.MAX_VALUE. Double precision floating point values outside this range are integers anyhow.
Unfortunately, why Math.round() returns long is unknown. Somebody made that decision, and he probably never gave an interview to tell us why. My guess is, that Math.round was designed to provide a better way (i.e., with rounding) for converting doubles to longs.
Like everyone else here I also don't know the answer, but thought someone might find this useful. I noticed that if you want to round a double to an int without casting, you can use the two round implementations long round(double) and int round(float) together:
double d = something;
int i = Math.round(Math.round(d));

Categories

Resources