7

I want to emulate the x86 extended precision type and perform arithmetic operations and casts to other types in Java.

I could try to implement it using BigDecimal, but covering all the special cases around NaNs, infinity, and casts would probably a tedious task. I am aware of some libraries that provide other floating types with a higher precision than double, but I want to have the same precision as the x86 80-bit float.

Is there a Java library that provides such a floating point type? If not, can you provide other hints that would allow to implement such a data type with less effort than coming up with a custom BigDecimal solution?

box
  • 3,156
  • 3
  • 26
  • 36
  • This sounds like an interesting problem, but why would you want to emulate the 80-bit extended precision format? Why not emulate something more precise? – Nayuki Oct 29 '15 at 16:04
  • it's for an interpreter that should provide the same results as other (compiled) implementations that can use the extended precision instructions. – box Oct 29 '15 at 16:07
  • 2
    In that case, you'll have fun emulating the quirky treatment of subnormal numbers compared to standard IEEE 754: https://en.wikipedia.org/wiki/Extended_precision#x86_Extended_Precision_Format – Nayuki Oct 29 '15 at 16:09
  • 6
    `BigDecimal` is _not_ suitable for this problem; `BigDecimal` represents _decimal_ numbers with powers of 10; the type you want represents _binary_ numbers with powers of 2, and mixing them is not really a good plan. – Louis Wasserman Oct 29 '15 at 16:37
  • 1
    "Not a good plan" is an understatement. "Doomed to fail by design" is more like it :) – Durandal Oct 29 '15 at 17:19
  • 1
    @NayukiMinase: The 80-bit floating point doesn't *have* subnormals in the same way that other types do, since it uses an explicit rather than implicit leading 1. A little bit of special handling is needed when storing results whose exponents would go below the minimum allowable value, but it's less trouble than with other formats which require special handling for both loads and stores. – supercat Oct 29 '15 at 20:52
  • @MarkDickinson: One of the advantages of the 80-bit format is that it's not necessarily to normalize values before or after additions or subtractions if one ensures that values are normalized before and after various other operations. If a addition or subtraction operation produces a subnormal value which is used as an operand to another addition or subtraction, no special handling is required. Types with an implied leading "1" require extra code when converting that leading "1" to an explicit 1, or if code doesn't internally use a format with an explicit "1", operations will need to... – supercat Oct 30 '15 at 16:38
  • ...use different code for the "normal" and "subnormal" case. The only real handling the 80-bit format requires for subnormal numbers is basically "if (exp < minimumExponent) { mantissa = roundedDiv2(mantissa >>> (minimumExponent-exp-1, stickyBit); exp = minimumExponent);} which would need to be done within the code for multiply or divide, when the sticky bit is available. – supercat Oct 30 '15 at 16:43

3 Answers3

4

If you know that your Java code will actually run on an x86 processor, implement the 80-bit arithmetic in assembly (or C, if the C compiler supports that) and invoke with JNI.

If you are targeting a particular non-x86 platform, look at qemu code. There should be some way to rip out just the part that does 80-bit float operations. (Edit: qemu's implementation is SoftFloat.). Call it with JNI.

If you truly want cross-platform pure-Java 80-bit arithmetic, you could probably still compare it against the C implementation in open-source CPU emulators to make sure you're addressing the right corner cases.

david
  • 997
  • 6
  • 15
  • I agree with your answer a lot. Dive into C/asm, or reusing existing C code, or build a new implementation comparing against native code or existing emulators. – Nayuki Oct 29 '15 at 19:50
  • I want to use pure Java code. I guess I have to look at an existing implementation written in another language as you suggested. – box Oct 31 '15 at 09:25
3

An 80-bit value should be best held as combination of a long (for the mantissa) and an int for the exponent and sign. For many operations, it will probably be most practical to place the upper and lower halves of the long into separate "long" values, so the code for addition of two numbers with matching signs and exponents would probably be something like:

long resultLo = (num1.mant & 0xFFFFFFFFL)+(num2.mant & 0xFFFFFFFFL);
long resultHi = (num1.mant >>> 32)+(num2.mant >>> 32)+(resultLo >>> 32);
result.exp = num1.exp; // Should match num2.exp
if (resultHi > 0xFFFFFFFFL) {
  exponent++;
  resultHi = (resultHi + ((resultHi & 2)>>>1)) >>> 1; // Round the result
}
rest.mant = (resultHi << 32) + resultLo;

A bit of a nuisance all around, but not completely unworkable. The key is to break numbers into pieces small enough that you can do all your math as type "long".

BTW, note that if one of the numbers did not originally have the same exponent, it will be necessary to keep track of whether any bits "fell off the end" when shifting it left or right to match the exponent of the first number, so as to be able to properly round the result afterward.

supercat
  • 77,689
  • 9
  • 166
  • 211
-3

This is a bit the reverse of the java strictfp option, that restricts the calculations to 8 bytes where it does 80 bits.

So my answer is run a JVM on a 64 bit machine, maybe in some hypervisor/OS VM, so you have a develop platform.

Joop Eggen
  • 107,315
  • 7
  • 83
  • 138
  • 2
    that does not work. strictfp allows some leeway but relying on the JIT to actually use 80 bit floats for intermediate values sounds wrong to me. also, strictfp (or a reverse option) does not affect the storage, which would still be in double bit width. – box Oct 29 '15 at 16:54
  • Even if you omit the `strictfp` keyword, a modern JVM will probably use x86 SSE instructions to do pure 64-bit or 32-bit FP math, instead of using x87's wider register. – Nayuki Oct 29 '15 at 19:48
  • Thanks for the shed light. So simply looking for a JVM using 80 bits and then use a VM to have a portable develop environment will not be as easy according to above comments. Java JVMs for embedded devices often have emulators; though they are often commercial, and Real Java is for 64 bits fp. – Joop Eggen Oct 29 '15 at 21:43