32

During the 1980s, prior to the 486 (well, strictly speaking, prior to the discontinuing of the 486SX in the nineties), IBM PCs and compatibles had hardware floating point only in the form of an optional coprocessor. Programmers responded to this in a variety of ways.

Some programs required the coprocessor.

Some would use it if present, fall back on software floating point if not. Presumably the format of floating-point numbers would not change between the two cases.

And some ignored the coprocessor and just used software floating point.

If you know you are going to be using software floating point, you might want to format the numbers differently. For example, make the exponent plus sign exactly 16 bits, to be loaded in just one instruction, and the mantissa 32 or 64 bits.

More subtly, IEEE implements a small but clever optimization in not actually storing the leading '1' bit that will always be present in a normal, nonzero number. But if you know you are going to be using the integer multiply instruction, you might want to eschew that in favor of immediately usable data.

Did any software floating point on IBM PCs and compatibles, actually deviate from IEEE format? (As opposed to the 8-bit machines, which mostly used a non-IEEE 40-bit format.)

5
  • 7
    IEEE FP was a late development in the history of floating-point, it wasn't even adopted by IEEE itself until 1985 (though Intel did implement the draft version earlier). And the "Implied leading 1" trick was common to most floating point formats long before IEEE-754 (I learned it on the PDP-11 in college, circa 1975). Mar 25 at 11:55
  • 2
    i was going to say that gcc has a non-standard float128 but fortunately their documentation states that the software implementation conforms to IEEE float128 standard. unfortunately for this question i can not use the gcc float128 as an example. Mar 25 at 14:04
  • 1
    If you expand to include calculators, the HP-41C used a 64-bit format, with 4 bits per digit. Mar 26 at 5:37
  • 1
    Even IEEE cannot agree on floats. IEEE-11073 is in current use and specifies a 32-bit float format that is not compatible with IEEE-754.
    – jpa
    Mar 26 at 9:10
  • 3
    By "did", you mean "still don't"? Because I use non-IEEE floats regularly and for example gcc uses them internally all the time. It's absolutely necessary when you need floating points larger than what the hardware can calculate.
    – pipe
    Mar 26 at 18:34

7 Answers 7

46

Turbo Pascal 2.x and the "ordinary" version of Turbo Pascal 3.x used a six-byte floating-point format which offered higher precision than an IEEE single-precision float, offering the advantages you described. I think it's unfortunate that more language implementations for platforms without FPUs don't offer non-IEEE-754 types, since they can offer significant performance advantages. Curiously, while some people view the IEEE-754 extended-precision types as being an "8087 weirdness", many 16-bit and 32-bit processors could perform computations with such types much more efficiently than with the IEEE-754 double-precision type.

10
  • 8
    And Turbo Pascal 3.02 offered a BCD aritmethic real type as well in a special edition of the compiler (and runtimes) offering 18 significant digits of precision.
    – tofro
    Mar 24 at 21:02
  • 2
    @tofro: There were three different Turbo Pascal executables with different kinds of floating-point support: general-purpose (six bytes), 8087-specific (I forget whether that used the 8 or 10-byte type), or BCD. The only way to select between different floating-point formats was to use a different compiler for each.
    – supercat
    Mar 24 at 21:37
  • 9
    The 6-byte Real format was retained at least through Turbo Pascal 6 and Borland Pascal 7. I wrote a faster replacement math library for it: TPL60N19.ZIP and BPL70N16.ZIP.
    – njuffa
    Mar 25 at 7:58
  • 2
    VAXes had the H 128 bit format that offered much higher precision also, circa 1980. Mar 25 at 12:01
  • 4
    The old pascal type was called Real, and later Real48 and it is still supported even in modern versions of Delphi, albeit only for backwards compatibility with legacy code.
    – J...
    Mar 25 at 18:04
37

The BASIC built into the ROM of the original IBM PC, as well as the BASICA and GW-BASIC programs, and therefore all software written in the language, used Microsoft Binary Format for floating-point numbers. This was based on Monte Davidoff’s floating-point routines for the Intel 8080, and similar to the single-precision format of the DEC VAX (but with a more convenient layout).

Microsoft changed to IEEE floating-point with QuickBASIC, although that program continued to optionally support MBF for backward compatibility.

1
  • 10
    And this backward compatibility produced one of the most unusual function names I've ever seen: fieeetombs().
    – Mark
    Mar 25 at 22:37
17

Half-precision wasn't a IEEE-754 standard format before 2008

Several earlier 16-bit floating point formats have existed including that of Hitachi's HD61810 DSP 2 of 1982, Scott's WIF [3] and the 3dfx Voodoo Graphics processor. [4]

ILM was searching for an image format that could handle a wide dynamic range, but without the hard drive and memory cost of single or double precision floating point). [5] The hardware-accelerated programmable shading group led by John Airey at SGI (Silicon Graphics) invented the s10e5 data type in 1997 as part of the 'bali' design effort. This is described in a SIGGRAPH 2000 paper [6] (see section 4.3) and further documented in US patent 7518615. [7] It was popularized by its use in the open-source OpenEXR image format.

Nvidia and Microsoft defined the half datatype in the Cg language, released in early 2002, and implemented it in silicon in the GeForce FX, released in late 2002. [8] Since then support for 16-bit floating point math in graphics cards has become very common.[ citation needed ]

The F16C extension in 2012 allows x86 processors to convert half-precision floats to and from single-precision floats with a machine instruction.

13

If we take "PC" not only as the ubiquitous IBM compatible x86 machine, and extend the range to any computer that claimed to be a "personal computer", than we have a lot more usages of non-IEEE format.

For example, the common BASIC of the ZX81* uses a 5 byte value for its numerical values, which are floating point only. I have never investigated whether it follows some standard.


*) The case has the words "personal computer" on its bottom.

1
  • I'd imagine that in the lab of the late Clive Sinclair, following standards would be grounds for dismissal :-)
    – Rich
    Mar 26 at 21:57
3

BASIC has quite a lot of floating-point formats. Besides the ones listed in the other answers there's also the Decimal type in Visual Basic

Holds signed 128-bit (16-byte) values representing 96-bit (12-byte) integer numbers scaled by a variable power of 10. The scaling factor specifies the number of digits to the right of the decimal point; it ranges from 0 through 2

Decimal Data Type (Visual Basic)

It's not the modern decimal type in IEEE-754. I guest because of this the Decimal type was also added into .NET framework


Objective-C has the NSDecimalNumber where

An instance can represent any number that can be expressed as mantissa x 10^exponent where mantissa is a decimal integer up to 38 digits long, and exponent is an integer from –128 through 127.

COBOL, being a financial programming language, also has a decimal floating-point type although I don't know the actual format

PL/I also has decimal floating-point but I don't know if it's available for x86 or not

1

All pre-SSE Windows software used a non-IEEE format: the format of the x87 FPU in "64-bit precision" mode.

Contrary to popular belief, this is not IEEE double. The format in registers has a 53-bit significand just like IEEE double, but it has the full 15-bit exponent range, not the 11-bit exponent of IEEE double. This causes subnormal values to carry excess precision, and overflow/underflow not to happen where they should, with the out-of-range values only collapsed (via rounding) to IEEE double range when registers are spilled to memory. This gives very weird, inconsistent, and non-IEEE-conforming semantics.

4
  • 1
    This is wrong. It belongs to the extended type in IEEE-754 standard and it was in fact created for the very reason of IEEE-754. They're both designed by Prof. William Kahan. See Function that returns whether the floating-point type is fully compliant to IEEE-754?
    – phuclv
    Mar 28 at 0:55
  • @phuclv: It does not belong to the extended types. If it were stored in memory with full 15-bit exponent, so that it maintained its values consistently, then it would be an IEEE extended type. But as it was/is used, it's a type which gains/loses precision unpredictably, which means it does not have IEEE semantics and is not an IEEE extended floating point type. Mar 28 at 4:36
  • who said that it doesn't have full 15-bit exponent? The format is 1 sign bit + 15 exponent bits + 64 significand bits. The unpredictability is because of the evaluation of intermediate expressions by the compiler. Changing FLT_EVAL_METHOD will reduce the unpredictability for float and double but long double is always evaluated in its full precision so there's no issue with it
    – phuclv
    Mar 28 at 5:06
  • @phuclv: On the Win32 ABI, long double is a 64-bit type. There is no type that can preserve the whole intermediate value when stored to memory. The whole point of my answer is that this ABI has the FPU running in a nonstandard mode that can't easily be treated as an IEEE extended type (treating it as one would require still storing it in memory with the 80-bit load/store instructions so that the whole exponent is preserved rather than inducing rounding at store time). Mar 28 at 14:03
1

The Hi-Tech C compiler version 7.80 for MS-DOS uses its own floating point format, derived from the format used in its earlier native CP/M compilers (up to v3.09).

From the assembly source file.

;   The format of a floating point number is as follows:
;
;           ------------
;           *   sign   *    1 bit
;           *----------*
;           * exponent *    7 bits
;           *----------*
;           * mantissa *    24 bits, normalized
;           ------------
;
;       Note that the number is stored with the mantissa in the
;       low order bytes, i.e. the sign is the most significant
;       bit of the most significant byte.

This format is defined in the documentation for the v3.09 Compiler, and the original compiler is being maintained here.

The floating point performance is benchmarked against peers (old and new), at here at z88dk.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.