Re: Question about rounding

Quote:

Is there a way in Java to round a number without using and external class such as Math and the method from the class to round up the number?

Why not use an external class? To use primitives, multiply the floating point variable by a multiplier of 10, cast to an int, cast back to the original type and divide by the same multiplier. Use the following syntax to cast a variable:

Code :

float fVal = 1.111f;
int iVal = (int)fVal;

Re: Question about rounding

Un-optimized, and probably overkill. However, it will maintain all exponents correctly, and works with the two infinities and NaN.

Code Java:

public static double round(double original_value)
{
long value = Double.doubleToLongBits(original_value);
// extract the exponent
long exponent = (value & 0x7FF0000000000000L) >> 52;
long mantissa = value & 0x000FFFFFFFFFFFFFL | 0x0010000000000000L;
exponent -= 0x3FFL;
if (exponent <= -2)
{
return 0;
}
else if (exponent == -1)
{
return 1;
}
else if (exponent < 52)
{
long mask = 0xFFFFFFFFFFFFFFFFL >>> 52 - exponent << 52 - exponent;
value &= mask;
if ((mantissa & 1L << 51 - exponent) != 0)
{
// round up
return Double.longBitsToDouble(value) + 1.;
}
// round down
return Double.longBitsToDouble(value);
}
else
{
return original_value; // no rounding needed
}
}

A similar solution exists for floats.

Re: Question about rounding

Quote:

(copeg) multiply the floating point variable by a multiplier of 10

I'm not sure - I didn't actually try it - how that would round 1.5 to 2. Does it work?

The way I would usually do this is through observing that 'nearest' is a two-way split: it's either next one up or previous one down. If you multiply a floating point number by two, then the integer part is 2x the original integer part for all fractional parts less than 0.5. If the fractional part is 0.5 or greater, the integer part of the doubled number is 2x + 1 the original integer part. If you add 1 to the doubled result and convert it to an integer, this new integer is either 2x + 2 or 2x + 1 depending on whether the original fractional part was greater than 0.5 or less than 0.5. Halving this integer gives you either x + 1 or x, depending on whether ... you know.

Quote:

Double.doubleToLongBits(

I was getting ready to pontificate about 'relying on implementation details', but on reading the API doc I see this method is badly named. Using Double.doubleToIEEE754DoubleBits(double) is of course an entirely reasonable and reliable way of doing it as long as IEEE754 is immutable.

Re: Question about rounding

Well, technically the Java Language Specifications spells out specifically how a double and float are represented. If the IEEE754 standard changes, then the Java Language Specification will just not comply to that standard :P

Of course, if that happens, a lot of hardware is going to break first since most hardware FPU's implement the current IEEE754 standard (or a previous version, which uses the same bit formatting).

Re: Question about rounding

Quote:

spells out specifically

It does spell out specifically, but not how double and float are implemented:

Quote:

float and double, which are **conceptually associated** with the single-precision 32-bit and double-precision 64-bit format IEEE 754 values

This is what I expect the Java specification to be: no commitment to implementation details at the binary level. It doesn't matter what the IEEE754 standard is at the binary level - the entire point of the JVM and the JLS is to provide a compatibility layer for the underlying platform on which Java applications run.

A *conceptual* association means you can use it in any way that you would use a 'raw' IEEE754 value, but no promise is made as regards its binary implementation. Note that with doubleToLongBits you are not inspecting the binary implementation of a double, but from the API doc for doubleToLongBits():

Quote:

a **representation** of the specified floating-point value

- it doesn't matter how double is implemented by the JVM and (as far as I know) no method exists to check its implementation. While doubleToLongBits returns an IEEE754-1985 binary representation from a Java-native double, your method will continue to work, by design.

Your approach is valid - you're obtaining a representation of a value that is no more and no less valid than the original, but which comes with some extra information you can test. It would be bad if you were testing the underlying implementation - but by specification ("conceptually associated") and implication (there's a method to create an IEE754 representation) you're not. Even if a Java double is implemented at the binary level as IEEE754 suggests, it doesn't affect the validity of your method (or my argument as to why your method *is* valid when at first glance it looks like a kludge) because you're not operating on the underlying implementation (which is usually a SlightlyBadThing), but a well-specified representation of that double value.

Are you familiar with JNI? I keep meaning to try out some long-lived compute-intensive code I have with a C++ implementation, but I'm scared of compromising the reliability of a pure-Java implementation. I see from a quick look at the WWW that when you write C++ code to manipulate Java doubles, the C++ code seems to always use a 'jdouble' type that must be from a C++-native library. I would have expected if there was any direct implementation similarity between Java doubles and C++ doubles that there'd be a trivial correspondence between Java double and C++ double. This page at SO makes me think that a lot of programming languages may be using 'conceptual association'!

Is there an open-source c/c++ implementation of IEEE-754 operations? - Stack Overflow

Does it look like I'm arguing with you? I'm still trying to explain why I *nearly* criticised your method, but didn't and still haven't. It's an entirely valid approach to a problem in double, but the reason *why* is a bit convoluted.

Re: Question about rounding

Ah, true that there's no guarantee of the ordering of the bits, only that they must be able to hold those values :P

most languages I know of don't actually manipulate floating point numbers (or even integer numbers) at that level normally. Instead, it's handled by hardware. That's the whole purpose of FPU's, which is where I think the "conceptual association" comes from. Personally I'm much more likely to trust hardware than software since many modern hardware companies "prove" their hardware, not just present test cases.

I have worked with JNI a little bit, it's fairly simple to use except for a few minor details which may catch you off guard. As far as I know, doubles in Java and in C++ are represented the same (due to a similar reliance on the underlying hardware implementation).

Re: Question about rounding

Quote:

Instead, it's handled by hardware

Hardware is a big space. Every compiled programming language will provide a maths library or attempt to use maths routines offered by the OS. The amount of work done in software and delegated to hardware will vary enormously from platform to platform. Check out some of these well known platforms:

ARM A9 - FPU is optional?:

Cortex-A9 Processor - ARM

Quote:

Optional NEON™ media and/or floating point processing engine

Some embedded x86 have no FPU:

Using software floating point on x86 linux - Stack Overflow

Partial support on MIPS:

Floating point - LinuxMIPS

The conceptual association in the JLS is certainly from the point of view of use of Java double: it's telling you you can do anything with a Java double you might expect to do with an IEEE754-1985 (not a -2008 one!) double. The nitty-gritty of floating point computation may be delegated by the JVM to whatever support exists on the target platform - but I suspect it could be difficult to guarantee that the results of double computations are identical across all JVMs unless they're carried out in software by the JVM itself.

Quote:

much more likely to trust hardware

Are you assuming 'black box so it must work'? :D This is a great James Gosling article which touches on a lot of the issue brought up by this discussion. You'll never use floating point again:

James Gosling: on the Java Road - Transcendental Meditation