How to do custom rounding of numbers in Java? - java

Suppose I want to round numbers that have mantissa greater than 0.3 'up' and those below 'down'.
How can I do it in Java?
The only thing that came to my mind was Math.round(), but I can't seem to make it follow a certain rule.

Math.floor(x+0.7) should do it.
This should work for an arbitrary mantissa. Just add the offset to the next integer to your value and round down.
The rounding is done by floor. Here is what the java API says to floor:
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.
This solution is similar to the one from #Thomas Stets, but imho it is easier to understand since rounding is done in only one direction.

Related

Is there a function to flip a number to positive to negative and negative to positive?

making a calculator for complex numbers and when dividing i need to use the complex conjugate of a number (basically just means flipping the number around the x-axis) aka make a number positive if it is negative, and negative if it is positive. Flipping the sign seems like something there should be a function for (abs(x) isn't enough here because it needs to go both ways). I am aware that i could just use if-tests to do this, but i feel like there should be some other way to do it.
There is no function in the Math class for flipping the sign of a number. You could try converting it to a big decimal and then call negate on that http://www.tutorialspoint.com/java/math/bigdecimal_negate.htm
Or just * -1
As the Complex Numbers cannot be Totally Ordered, the concept of a negative complex number, relative to a specified zero, is not defined. However, the negative of a complex number is defined as follows:
Let
z=a+ib be a complex number.
Then the negative of z is defined as:
−z=−a−ib
Examples:
The negative of 2+3i is −2−3i
The negative of 4−5i is −4+5i.

double numbers are not too accurate

I've wrote a method for polynomial long division. And it works perfect with "good" polynomials. Under "good" I mean coefficients that divides accurate. Today I've faced with issue when tried to divide 2*x^3-18*x^2+.... / 7.00000(much zeros)0000028*x^2 + 5*x + ... After division 2*x^3 / 7.000...000028*x^2 I got 0.285714....53*x. On next step we need to multiply 0.2857....53*x on 7.00000...0000028*x^2 + 5*x + .. and subtract it from dividend polynomial 2*x^3-18*x^2+... and get new polynomial with degree = 2. But because of problem with double type I actually got polynomial 2.220....E-16*x^3 - 6*x^2 + .... I know that it is in fact zero near the x^3. I do not want to invent smth new and strange, that is why I am asking how to resolve it beautifully and correctly. Thanks.
Many division results such as 1/7 cannot be represented exactly in either double or BigDecimal. If you go with BigDecimal you would have to pick a number of digits to preserve, and deal with rounding error. For double, you get more convenient arithmetic, but a fixed number of significant bits.
You have two options.
One is to handle rounding error. When a result is very close to zero, so close that it is probably due to rounding error, treat it as zero. I don't know whether that will work for your algorithm or not. If you go this way, you can use either double or BigDecimal.
The second option is to use a rational number package. In rational number arithmetic all division results can be represented exactly. 1/7 remains 1/7, without being rounded to a terminating decimal or binary fraction. If you go this way, search for "java rational number" (no quotes) and decide which one you like best.

How to round a double/float to BINARY precision?

I am writing tests for code performing calculations on floating point numbers. Quite expectedly, the results are rarely exact and I would like to set a tolerance between the calculated and expected result. I have verified that in practice, with double precision, the results are always correct after rounding of last two significant decimals, but usually after rounding the last decimal. I am aware of the format in which doubles and floats are stored, as well as the two main methods of rounding (precise via BigDecimal and faster via multiplication, math.round and division). As the mantissa is stored in binary however, is there a way to perform rounding using base 2 rather than 10?
Just clearing the last 3 bits almost always yields equal results, but if I could push it and instead 'add 2' to the mantissa if its second least significast bit is set, I could probably reach the limit of accuracy. This would be easy enough, expect I have no idea how to handle overflow (when all bits 52-1 are set).
A Java solution would be preferred, but I could probably port one for another language if I understood it.
EDIT:
As part of the problem was that my code was generic with regards to arithmetic (relying on scala.Numeric type class), what I did was an incorporation of rounding suggested in the answer into a new numeric type, which carried the calculated number (floating point in this case) and rounding error, essentially representing a range instead of a point. I then overrode equals so that two numbers are equal if their error ranges overlap (and they share arithmetic, i.e. the number type).
Yes, rounding off binary digits makes more sense than going through BigDecimal and can be implemented very efficiently if you are not worried about being within a small factor of Double.MAX_VALUE.
You can round a floating-point double value x with the following sequence in Java (untested):
double t = 9 * x; // beware: this overflows if x is too close to Double.MAX_VALUE
double y = x - t + t;
After this sequence, y should contain the rounded value. Adjust the distance between the two set bits in the constant 9 in order to adjust the number of bits that are rounded off. The value 3 rounds off one bit. The value 5 rounds off two bits. The value 17 rounds off four bits, and so on.
This sequence of instruction is attributed to Veltkamp and is typically used in “Dekker multiplication”. This page has some references.

Nan from maths equation

Hi I have the following equation in a piece of java code:
double z = 0.002378 * (Math.pow((1 - (Math.pow(6.875, -6) * y)), 4.2561));
when I set y to be very large values, i.e 200000 I get Nan (Not a number) It's working okay at slightly lower values, 130000
Can anyone tell me why that is?
Additionally I've tried to port the above code from an original BASIC program:
.002378*(1-(6.875*10^-6*ALT))^4.2561
I may have done it wrong? The order of operations isn't very explicit in the BASIC code
Thanks
As the Javadoc for Math.pow explains:
If the first argument is finite and less than zero [… and] the second argument is finite and not an integer, then the result is NaN.
So whenever your y is great enough that 1 - (Math.pow(6.875, -6) * y is negative, you'll get NaN.
(This makes sense when you consider the underlying math. A negative number to a non-integer power is not a real number, and double has no way to represent complex numbers.)
Edited for updated question:
Your Basic code has 6.875*10^-6 (meaning 6.875 × 10−6), but your Java code has Math.pow(6.875, -6) (meaning 6.875−6), which is a somewhat greater value, so your Java code triggers this problem for somewhat smaller values of y. This may be why you're seeing this problem now. To match the Basic code, you should change Math.pow(6.875, -6) to 6.875e-6.
Raising a negative number to a non-integer power results in an imaginary number in complex number mathematics, a NaN in Java arithmetic. If you really need to do that calculation, you need a complex number package. However, it is more likely that there is an error in your equation or you are trying to use it outside its range of validity.
Negtive number with real number power may get NAN

Weird floor rounding [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Moving decimal places over in a double
I am having this weird problem in Java, I have following code:
double velocity = -0.07;
System.out.println("raw value " + velocity*200 );
System.out.println("floored value " + Math.floor(velocity*200) );
I have following output:
raw value -14.000000000000002
floored value -15.0
Those traling 0002 screw everything up, and BTW there should not be that traling 2, I think it should be all zeroes after decimal point, can I get rid of that 2?
Update: Thanks for help, Guys do you know any way to make floor rounding on BigDecimal object without calling doubleValue method?
Because floor(-14.000000000000002) is indeed -15!
You see, floor is defined as the maximal whole number less or equal to the argument. As -14.000000000000002 is not a whole number, the closest whole number downwards is -15.
Well, now let's clear why -0.07 * 200 is not exactly -14. This is because the inner representation of floating-point numbers is in base 2, so the fractions where the denominator is not a power of 2 cannot be represented with 100% precision. (The same way as you cannot represent 1/3 as the decimal fraction with finite amount of decimal places.) So, the value of velocity is not exactly -0.07. (When the compiler sees the constant -0.07, it silently replaces it with a binary fraction which is quite close to -0.07, but not actually equal to.) This is why velocity * 200 is not exactly -14.
From The Floating-Point Guide:
Why don’t my numbers, like 0.1 + 0.2 add up to a nice round 0.3, and instead I get a weird result like 0.30000000000000004?
Because internally, computers use a format (binary floating-point)
that cannot accurately represent a number like 0.1, 0.2 or 0.3 at all.
When the code is compiled or interpreted, your “0.1” is already
rounded to the nearest number in that format, which results in a small
rounding error even before the calculation happens.
If you need numbers that exactly add up to specific expected values, you cannot use double. Read the linked-to site for details.
Use BigDecimal... The problem above is a well-known rounding problem with the representation schemes used on a computer with finite-memory. The problem is that the answer is repetitive in the binary (that is, base 2) system (i.e. like 1/3 = 0.33333333... with decimal) and cannot be presented correctly. A good example of this is 1/10 = 0.1 which is 0.000110011001100110011001100110011... in binary. After some point the 1s and 0s have to end, causing the perceived error.
Hope you're not working on life-critical stuff... for example http://www.ima.umn.edu/~arnold/disasters/patriot.html. 28 people lost their lives due to a rounding error.
Java doubles follow the IEEE 754 floating-point arithmetic, which can't represent every single real number with infinite accuracy. This round up is normal. You can't get rid of it in the internal representation. You can of course use String.format to print the result.

Categories