On 01/10/2026 03:33, bart wrote:The latter appears to be a default on ARM64 Linux.
On 01/10/2026 01:47, Lawrence D’Oliveiro wrote:
A couple of things stand out immediately: one is that the “long
double” type doesn’t seem to make use of all the 128 bits it
occupies. I was expecting a mantissa length closer to 100 bits,
but it’s nowhere near that.
Probably it uses Intel's 80-bit x87 FPU format. That uses a 64-bit mantissa (with explicit top bit).
Yes, that's the default for "long double" in the standard x86-64 ABI.
On 32-bit x86, these 10-byte doubles were often stored in 12-byte
(96-bit) containers for better alignment, but I don't know the ABI
standards here.
On 64-bit x86, for better alignment they are stored in 16-byte
containers. The rest of the space will be padding.
gcc supports "-mlong-double-64", "-mlong-double-80" and
"-mlong-double-128" flags.
With 64-bit long doubles, they are
effectively the same as doubles, and thus faster. 80-bit long
doubles are the standard, while 128-bit long doubles give
quad-precision range and precision, but must be handled in software
through the gcc-provided "libquad" library functions.
You can also use the _Float128 or _Float128x types, which are
optional types in the C standards (along with 16, 32 and 64-bit
versions). The "x" types are for calculations and might be bigger
than their name applies, while the non-x types are "interchange"
types that have the same format on all systems.
10 bytes would be an odd size though, so it's rounded up to 16
bytes in the implementation.
I don't know if current hardware would directly support a full 128
bits, or it needs to be emulated.
IBM's POWER processors are, I think, the only cpus with hardware quad-precision floating point that are realistic. RISC-V has the Q extensions specified, but I do not believe anyone actually makes
RISC-V cores with quad floating point.
However, float limits (in float.h) should give a clue as to the
actual range and precision.
Yes.
You can also just write some code in godbolt.org, and see if it calls library functions like "__multf3" instead of generating hardware instructions, as you play around with the compiler flags.
On Thu, 1 Oct 2026 10:17:57 +0200
David Brown <[email protected]> wrote:
On 01/10/2026 03:33, bart wrote:
On 01/10/2026 01:47, Lawrence D’Oliveiro wrote:
A couple of things stand out immediately: one is that the “long
double” type doesn’t seem to make use of all the 128 bits it
occupies. I was expecting a mantissa length closer to 100 bits,
but it’s nowhere near that.
Probably it uses Intel's 80-bit x87 FPU format. That uses a 64-bit
mantissa (with explicit top bit).
Yes, that's the default for "long double" in the standard x86-64 ABI.
On 32-bit x86, these 10-byte doubles were often stored in 12-byte
(96-bit) containers for better alignment, but I don't know the ABI
standards here.
On 64-bit x86, for better alignment they are stored in 16-byte
containers. The rest of the space will be padding.
gcc supports "-mlong-double-64", "-mlong-double-80" and
"-mlong-double-128" flags.
The latter appears to be a default on ARM64 Linux.
With 64-bit long doubles, they are
effectively the same as doubles, and thus faster. 80-bit long
doubles are the standard, while 128-bit long doubles give
quad-precision range and precision, but must be handled in software
through the gcc-provided "libquad" library functions.
It is more complicated than that.
libquadmath supplies 128-bit equivalents of of standard C math library functions and functions for conveersion betwen fp128 and strings.
But basic arithmetic operations are coming from other source. One would suspect libgcc, but reality is more complicated than just that. It
seems that Jakub Jelinek knows details, but I am not sure that there is somebody else that knows all of them for all platforms.
You can also use the _Float128 or _Float128x types, which are
optional types in the C standards (along with 16, 32 and 64-bit
versions). The "x" types are for calculations and might be bigger
than their name applies, while the non-x types are "interchange"
types that have the same format on all systems.
Another name supported on many platforms is __float128.
10 bytes would be an odd size though, so it's rounded up to 16
bytes in the implementation.
I don't know if current hardware would directly support a full 128
bits, or it needs to be emulated.
IBM's POWER processors are, I think, the only cpus with hardware
quad-precision floating point that are realistic. RISC-V has the Q
extensions specified, but I do not believe anyone actually makes
RISC-V cores with quad floating point.
Don't forget IBM Z.
BTW, the next generation of IBM Z chips will run ARM64 natively
alongside Z. I wonder if it would mativate IBM to ask ARM Inc to add
128-bit BFP (and may be DFP) as optional extension(s) to Arm ISA.
On 01/10/2026 13:12, Michael S wrote:Significantly slower, yes.
On Thu, 1 Oct 2026 10:17:57 +0200
David Brown <[email protected]> wrote:
On 01/10/2026 03:33, bart wrote:
On 01/10/2026 01:47, Lawrence D’Oliveiro wrote:
A couple of things stand out immediately: one is that the “long >>>>> double†type doesn’t seem to make use of all the 128 bits it >>>>> occupies. I was expecting a mantissa length closer to 100 bits,
but it’s nowhere near that.
Probably it uses Intel's 80-bit x87 FPU format. That uses a 64-bit
mantissa (with explicit top bit).
Yes, that's the default for "long double" in the standard x86-64 ABI.>>> >>> On 32-bit x86, these 10-byte doubles were often stored in 12-byte
(96-bit) containers for better alignment, but I don't know the ABI
standards here.
On 64-bit x86, for better alignment they are stored in 16-byte
containers. The rest of the space will be padding.
gcc supports "-mlong-double-64", "-mlong-double-80" and
"-mlong-double-128" flags.
The latter appears to be a default on ARM64 Linux.
That makes sense. Although software 128-bit floating point is going to
be very slow compared to hardware 64-bit, the reason you would use "long double" is to get more than "double".
David Brown wrote:
On 01/10/2026 13:12, Michael S wrote:
On Thu, 1 Oct 2026 10:17:57 +0200
David Brown <[email protected]> wrote:
On 01/10/2026 03:33, bart wrote:
On 01/10/2026 01:47, Lawrence D’Oliveiro wrote:
A couple of things stand out immediately: one is that the “long >>>>>> double†type doesn’t seem to make use of all the 128 bits it
occupies. I was expecting a mantissa length closer to 100 bits,
but it’s nowhere near that.
Probably it uses Intel's 80-bit x87 FPU format. That uses a 64-bit
mantissa (with explicit top bit).
Yes, that's the default for "long double" in the standard x86-64 ABI.
On 32-bit x86, these 10-byte doubles were often stored in 12-byte
(96-bit) containers for better alignment, but I don't know the ABI
standards here.
On 64-bit x86, for better alignment they are stored in 16-byte
containers. The rest of the space will be padding.
gcc supports "-mlong-double-64", "-mlong-double-80" and
"-mlong-double-128" flags.
The latter appears to be a default on ARM64 Linux.
That makes sense. Although software 128-bit floating point is going
to be very slow compared to hardware 64-bit, the reason you would use
"long double" is to get more than "double".
Significantly slower, yes.
For Mill we figured out that if the HW provided a small number of helper functions (easy to do in HW, much harder in SW), then you can do most
ops in maybe 5x the HW cycle count.
Without that help, you need to manually extract sign/exp/
mantissa(inserting leading bit unless subnormal), then for add/sub you
must normalize the smaller number (including sticky bit), do the add, normalize again, then merge with exponent and round.
For FMUL you don't pre-normalize (so no extra cycles for subnormal), but
you have to handle the potential for up to 111 bits of post-normalization.
Michael S is my current benchmark source here, I'd guess FADD128 in less than 40 cycles, about the same for FMUL128, while FMAC128 has to be a
little bit harder with a _very_ wide intermediate result.
Terje
... much like how cheap support for "double" doesn't mean that no
one uses "float"...).
David Brown wrote:
On 01/10/2026 13:12, Michael S wrote:
On Thu, 1 Oct 2026 10:17:57 +0200
David Brown <[email protected]> wrote:
On 01/10/2026 03:33, bart wrote:
On 01/10/2026 01:47, Lawrence D’Oliveiro wrote:
A couple of things stand out immediately: one is that the
“long double†type doesn’t seem to make use of all the
128 bits it occupies. I was expecting a mantissa length closer
to 100 bits, but it’s nowhere near that.
Probably it uses Intel's 80-bit x87 FPU format. That uses a
64-bit mantissa (with explicit top bit).
Yes, that's the default for "long double" in the standard x86-64
ABI.
On 32-bit x86, these 10-byte doubles were often stored in 12-byte
(96-bit) containers for better alignment, but I don't know the ABI
standards here.
On 64-bit x86, for better alignment they are stored in 16-byte
containers. The rest of the space will be padding.
gcc supports "-mlong-double-64", "-mlong-double-80" and
"-mlong-double-128" flags.
The latter appears to be a default on ARM64 Linux.
That makes sense. Although software 128-bit floating point is
going to be very slow compared to hardware 64-bit, the reason you
would use "long double" is to get more than "double".
Significantly slower, yes.
For Mill we figured out that if the HW provided a small number of
helper functions (easy to do in HW, much harder in SW), then you can
do most ops in maybe 5x the HW cycle count.
Without that help, you need to manually extract
sign/exp/mantissa(inserting leading bit unless subnormal), then for
add/sub you must normalize the smaller number (including sticky bit),
do the add, normalize again, then merge with exponent and round.
For FMUL you don't pre-normalize (so no extra cycles for subnormal),
but you have to handle the potential for up to 111 bits of post-normalization.
Michael S is my current benchmark source here, I'd guess FADD128 in
less than 40 cycles, about the same for FMUL128, while FMAC128 has to
be a little bit harder with a _very_ wide intermediate result.
Terje
On Fri, 2 Oct 2026 20:35:56 +0200So what you are saying is the my guesstimate was in the right ballpark,
Terje Mathisen <[email protected]> wrote:
David Brown wrote:
On 01/10/2026 13:12, Michael S wrote:
On Thu, 1 Oct 2026 10:17:57 +0200
David Brown <[email protected]> wrote:
On 01/10/2026 03:33, bart wrote:
On 01/10/2026 01:47, Lawrence D’Oliveiro wrote:
A couple of things stand out immediately: one is that the
“long double†type doesn’t seem to make use of all the
128 bits it occupies. I was expecting a mantissa length closer
to 100 bits, but it’s nowhere near that.
Probably it uses Intel's 80-bit x87 FPU format. That uses a
64-bit mantissa (with explicit top bit).
Yes, that's the default for "long double" in the standard x86-64
ABI.
On 32-bit x86, these 10-byte doubles were often stored in 12-byte
(96-bit) containers for better alignment, but I don't know the ABI
standards here.
On 64-bit x86, for better alignment they are stored in 16-byte
containers. The rest of the space will be padding.
gcc supports "-mlong-double-64", "-mlong-double-80" and
"-mlong-double-128" flags.
The latter appears to be a default on ARM64 Linux.
That makes sense. Although software 128-bit floating point is
going to be very slow compared to hardware 64-bit, the reason you
would use "long double" is to get more than "double".
Significantly slower, yes.
For Mill we figured out that if the HW provided a small number of
helper functions (easy to do in HW, much harder in SW), then you can
do most ops in maybe 5x the HW cycle count.
Without that help, you need to manually extract
sign/exp/mantissa(inserting leading bit unless subnormal), then for
add/sub you must normalize the smaller number (including sticky bit),
do the add, normalize again, then merge with exponent and round.
For FMUL you don't pre-normalize (so no extra cycles for subnormal),
but you have to handle the potential for up to 111 bits of
post-normalization.
Michael S is my current benchmark source here, I'd guess FADD128 in
less than 40 cycles, about the same for FMUL128, while FMAC128 has to
be a little bit harder with a _very_ wide intermediate result.
Terje
Of course, an actual cycle count depends on what you measure, latency
or throughput, on your CPU, on how many corners you are willing to cut
w.r.t. support for rounding modes and for FP exceptions and on the ABI.> Current x86-64 SYSV ABI is quite problematic and rather far from
well-thought.
Windows currently has no official FP128 ABI at all, the closest to
official is the ABI implemented by gcc under msys2. It is even more problematic than SysV.
As far as I am concerned, the most problematic part of both ABIs is
program status word that is shared with FP32/64. But registers choice
is also bad.
According to what I hear from Thomas Koenig, in Fortran quite a few
corners can be cut without violating language assumptions. For C it
would be harder.
With most corners cut, i.e. without non-default rounding modes and
without support for Inexact exception, and for throughput rather than
latency Zen3/Linux runs at ~50 clocks per FMUL+FADD. I never tried to separate between the two. Would think that they are about the same.
Pay attention, that nearly all cost of implementing non-default
rounding mode is because of need to read rounding mode from HW register.
The same applies to implementing Inexact exception - the main cost is
update of HW register.
Michael S wrote:
On Fri, 2 Oct 2026 20:35:56 +0200
Terje Mathisen <[email protected]> wrote:
David Brown wrote:
On 01/10/2026 13:12, Michael S wrote:
On Thu, 1 Oct 2026 10:17:57 +0200
David Brown <[email protected]> wrote:
On 01/10/2026 03:33, bart wrote:
On 01/10/2026 01:47, Lawrence D’Oliveiro wrote: >>>>>>> A couple of things stand out immediately: one is that the
“long double†type doesn’t seem to make
use of all the 128 bits it occupies. I was expecting a
mantissa length closer to 100 bits, but it’s nowhere >>>>>>> near that.
Probably it uses Intel's 80-bit x87 FPU format. That uses a
64-bit mantissa (with explicit top bit).
Yes, that's the default for "long double" in the standard x86-64
ABI.
On 32-bit x86, these 10-byte doubles were often stored in
12-byte (96-bit) containers for better alignment, but I don't
know the ABI standards here.
On 64-bit x86, for better alignment they are stored in 16-byte
containers. The rest of the space will be padding.
gcc supports "-mlong-double-64", "-mlong-double-80" and
"-mlong-double-128" flags.
The latter appears to be a default on ARM64 Linux.
That makes sense. Although software 128-bit floating point is
going to be very slow compared to hardware 64-bit, the reason you
would use "long double" is to get more than "double".
Significantly slower, yes.
For Mill we figured out that if the HW provided a small number of
helper functions (easy to do in HW, much harder in SW), then you
can do most ops in maybe 5x the HW cycle count.
Without that help, you need to manually extract
sign/exp/mantissa(inserting leading bit unless subnormal), then for
add/sub you must normalize the smaller number (including sticky
bit), do the add, normalize again, then merge with exponent and
round.
For FMUL you don't pre-normalize (so no extra cycles for
subnormal), but you have to handle the potential for up to 111
bits of post-normalization.
Michael S is my current benchmark source here, I'd guess FADD128 in
less than 40 cycles, about the same for FMUL128, while FMAC128 has
to be a little bit harder with a _very_ wide intermediate result.
Terje
Of course, an actual cycle count depends on what you measure,
latency or throughput, on your CPU, on how many corners you are
willing to cut w.r.t. support for rounding modes and for FP
exceptions and on the ABI. Current x86-64 SYSV ABI is quite
problematic and rather far from well-thought.
Windows currently has no official FP128 ABI at all, the closest to
official is the ABI implemented by gcc under msys2. It is even more problematic than SysV.
As far as I am concerned, the most problematic part of both ABIs is
program status word that is shared with FP32/64. But registers
choice is also bad.
According to what I hear from Thomas Koenig, in Fortran quite a few
corners can be cut without violating language assumptions. For C it
would be harder.
With most corners cut, i.e. without non-default rounding modes and
without support for Inexact exception, and for throughput rather
than latency Zen3/Linux runs at ~50 clocks per FMUL+FADD. I never
tried to separate between the two. Would think that they are about
the same.
Pay attention, that nearly all cost of implementing non-default
rounding mode is because of need to read rounding mode from HW
register. The same applies to implementing Inexact exception - the
main cost is update of HW register.
So what you are saying is the my guesstimate was in the right
ballpark, but that it would be far better for fp128 to be a totally
separate environment, with all flags and modes maintained in the
library instead of sharing anything with the HW?
Regarding rounding modes, in my own Mill work a single 64-bit const
contain all the rounding rules for the four non-truncate
alternatives, so this didn't really cost much.
Terje
So what you are saying is the my guesstimate was in the right ballpark,
but that it would be far better for fp128 to be a totally separate environment, with all flags and modes maintained in the library instead
of sharing anything with the HW?
On Fri, 2 Oct 2026 17:13:35 -0500, BGB wrote:
... much like how cheap support for "double" doesn't mean that no
one uses "float"...).
Double is pretty much the default precision, though. High-level
languages like Python and JavaScript only support one real-number
precision, and that’s double.
Even the naming of the C run-time routines -- an “f” suffix denotes single precision, “l” denotes long double, while no suffix defaults to meaning double.
On Sat, 3 Oct 2026 20:22:51 +0200I used memory/stack for all parameters in the limited functionality
Terje Mathisen <[email protected]> wrote:
Michael S wrote:
On Fri, 2 Oct 2026 20:35:56 +0200
Terje Mathisen <[email protected]> wrote:
David Brown wrote:
On 01/10/2026 13:12, Michael S wrote:
On Thu, 1 Oct 2026 10:17:57 +0200
David Brown <[email protected]> wrote:
On 01/10/2026 03:33, bart wrote:
On 01/10/2026 01:47, Lawrence D’Oliveiro wrote:
A couple of things stand out immediately: one is that the
“long double†type doesn’t seem to make
use of all the 128 bits it occupies. I was expecting a
mantissa length closer to 100 bits, but it’s nowhere
near that.
Probably it uses Intel's 80-bit x87 FPU format. That uses a
64-bit mantissa (with explicit top bit).
Yes, that's the default for "long double" in the standard x86-64 >>>>>>> ABI.
On 32-bit x86, these 10-byte doubles were often stored in
12-byte (96-bit) containers for better alignment, but I don't
know the ABI standards here.
On 64-bit x86, for better alignment they are stored in 16-byte
containers. The rest of the space will be padding.
gcc supports "-mlong-double-64", "-mlong-double-80" and
"-mlong-double-128" flags.
The latter appears to be a default on ARM64 Linux.
That makes sense. Although software 128-bit floating point is >>>>> going to be very slow compared to hardware 64-bit, the reason you
would use "long double" is to get more than "double".
Significantly slower, yes.
For Mill we figured out that if the HW provided a small number of
helper functions (easy to do in HW, much harder in SW), then you
can do most ops in maybe 5x the HW cycle count.
Without that help, you need to manually extract
sign/exp/mantissa(inserting leading bit unless subnormal), then for
add/sub you must normalize the smaller number (including sticky
bit), do the add, normalize again, then merge with exponent and
round.
For FMUL you don't pre-normalize (so no extra cycles for
subnormal), but you have to handle the potential for up to 111
bits of post-normalization.
Michael S is my current benchmark source here, I'd guess FADD128 in
less than 40 cycles, about the same for FMUL128, while FMAC128 has
to be a little bit harder with a _very_ wide intermediate result.
Terje
Of course, an actual cycle count depends on what you measure,
latency or throughput, on your CPU, on how many corners you are
willing to cut w.r.t. support for rounding modes and for FP
exceptions and on the ABI. Current x86-64 SYSV ABI is quite
problematic and rather far from well-thought.
Windows currently has no official FP128 ABI at all, the closest to
official is the ABI implemented by gcc under msys2. It is even more
problematic than SysV.
As far as I am concerned, the most problematic part of both ABIs is
program status word that is shared with FP32/64. But registers
choice is also bad.
According to what I hear from Thomas Koenig, in Fortran quite a few
corners can be cut without violating language assumptions. For C it
would be harder.
With most corners cut, i.e. without non-default rounding modes and
without support for Inexact exception, and for throughput rather
than latency Zen3/Linux runs at ~50 clocks per FMUL+FADD. I never
tried to separate between the two. Would think that they are about
the same.
Pay attention, that nearly all cost of implementing non-default
rounding mode is because of need to read rounding mode from HW
register. The same applies to implementing Inexact exception - the
main cost is update of HW register.
So what you are saying is the my guesstimate was in the right
ballpark, but that it would be far better for fp128 to be a totally
separate environment, with all flags and modes maintained in the
library instead of sharing anything with the HW?
Yes.
Also it would be better if parameteres/return values to/from
support routines (i.e. fadd128, fmul128 etc) passed either in GPRs or in memory instead of SIMD registers.
Can you trap on updates to those registers? That would make it muchRegarding rounding modes, in my own Mill work a single 64-bit const
contain all the rounding rules for the four non-truncate
alternatives, so this didn't really cost much.
And what happens when FP32 implemented in HW, but FP64 emoulated in
software as is the most common case in ARM-based MCUs?
It is also kinda interesting that people 40 years ago seemingly knew
which format was best for general purpose use, and the needle hasn't
really moved since then.
On Sat, 3 Oct 2026 15:20:39 -0500, BGB wrote:
It is also kinda interesting that people 40 years ago seemingly knew
which format was best for general purpose use, and the needle hasn't
really moved since then.
You mean the Bell Labs C/Unix folks?
I don’t think their design choice was very popular at the time. It simplified the design and implementation of the C language, which I
think was their primary consideration. I imagine the FORTRAN folks
threw their hands up in horror.
On Sat, 3 Oct 2026 20:22:51 +0200
Terje Mathisen <[email protected]> wrote:
Michael S wrote:
On Fri, 2 Oct 2026 20:35:56 +0200
Terje Mathisen <[email protected]> wrote:
David Brown wrote:
On 01/10/2026 13:12, Michael S wrote:
On Thu, 1 Oct 2026 10:17:57 +0200
David Brown <[email protected]> wrote:
On 01/10/2026 03:33, bart wrote:
On 01/10/2026 01:47, Lawrence D’Oliveiro wrote: >>>>>>> A couple of things stand out immediately: one is that the
“long double†type doesn’t seem to make
use of all the 128 bits it occupies. I was expecting a
mantissa length closer to 100 bits, but it’s nowhere
near that.
Probably it uses Intel's 80-bit x87 FPU format. That uses a
64-bit mantissa (with explicit top bit).
Yes, that's the default for "long double" in the standard x86-64 >>>>> ABI.
On 32-bit x86, these 10-byte doubles were often stored in
12-byte (96-bit) containers for better alignment, but I don't
know the ABI standards here.
On 64-bit x86, for better alignment they are stored in 16-byte
containers. The rest of the space will be padding.
gcc supports "-mlong-double-64", "-mlong-double-80" and
"-mlong-double-128" flags.
The latter appears to be a default on ARM64 Linux.
That makes sense. Although software 128-bit floating point is
going to be very slow compared to hardware 64-bit, the reason you
would use "long double" is to get more than "double".
Significantly slower, yes.
For Mill we figured out that if the HW provided a small number of
helper functions (easy to do in HW, much harder in SW), then you
can do most ops in maybe 5x the HW cycle count.
Without that help, you need to manually extract
sign/exp/mantissa(inserting leading bit unless subnormal), then for
add/sub you must normalize the smaller number (including sticky
bit), do the add, normalize again, then merge with exponent and
round.
For FMUL you don't pre-normalize (so no extra cycles for
subnormal), but you have to handle the potential for up to 111
bits of post-normalization.
Michael S is my current benchmark source here, I'd guess FADD128 in
less than 40 cycles, about the same for FMUL128, while FMAC128 has
to be a little bit harder with a _very_ wide intermediate result.
Terje
Of course, an actual cycle count depends on what you measure,
latency or throughput, on your CPU, on how many corners you are
willing to cut w.r.t. support for rounding modes and for FP
exceptions and on the ABI. Current x86-64 SYSV ABI is quite
problematic and rather far from well-thought.
Windows currently has no official FP128 ABI at all, the closest to official is the ABI implemented by gcc under msys2. It is even more problematic than SysV.
As far as I am concerned, the most problematic part of both ABIs is program status word that is shared with FP32/64. But registers
choice is also bad.
According to what I hear from Thomas Koenig, in Fortran quite a few corners can be cut without violating language assumptions. For C it
would be harder.
With most corners cut, i.e. without non-default rounding modes and without support for Inexact exception, and for throughput rather
than latency Zen3/Linux runs at ~50 clocks per FMUL+FADD. I never
tried to separate between the two. Would think that they are about
the same.
Pay attention, that nearly all cost of implementing non-default
rounding mode is because of need to read rounding mode from HW
register. The same applies to implementing Inexact exception - the
main cost is update of HW register.
So what you are saying is the my guesstimate was in the right
ballpark, but that it would be far better for fp128 to be a totally separate environment, with all flags and modes maintained in the
library instead of sharing anything with the HW?
Yes.
Also it would be better if parameteres/return values to/from
support routines (i.e. fadd128, fmul128 etc) passed either in GPRs or in memory instead of SIMD registers.
Regarding rounding modes, in my own Mill work a single 64-bit const contain all the rounding rules for the four non-truncate
alternatives, so this didn't really cost much.
And what happens when FP32 implemented in HW, but FP64 emoulated in
software as is the most common case in ARM-based MCUs?
Terje
On 10/3/2026 4:46 PM, Lawrence D’Oliveiro wrote:
On Sat, 3 Oct 2026 15:20:39 -0500, BGB wrote:
It is also kinda interesting that people 40 years ago seemingly
knew which format was best for general purpose use, and the needle
hasn't really moved since then.
You mean the Bell Labs C/Unix folks?
I was more thinking of things around the time of the IEEE-754
standard, which defined single/double, which mapped 1:1 with C
float/double.
And, double was the default, and also the most useful...
And, they chose double rather than single as the default, despite double being gigantic compared with the integer or pointer types in use at the
time.
On Thu, 1 Oct 2026 10:17:57 +0200
David Brown <[email protected]> wrote:
On 01/10/2026 03:33, bart wrote:
On 01/10/2026 01:47, Lawrence D’Oliveiro wrote:
A couple of things stand out immediately: one is that the “long
double” type doesn’t seem to make use of all the 128 bits it
occupies. I was expecting a mantissa length closer to 100 bits,
but it’s nowhere near that.
Probably it uses Intel's 80-bit x87 FPU format. That uses a 64-bit mantissa (with explicit top bit).
Yes, that's the default for "long double" in the standard x86-64 ABI.
On 32-bit x86, these 10-byte doubles were often stored in 12-byte
(96-bit) containers for better alignment, but I don't know the ABI standards here.
On 64-bit x86, for better alignment they are stored in 16-byte
containers. The rest of the space will be padding.
gcc supports "-mlong-double-64", "-mlong-double-80" and "-mlong-double-128" flags.
The latter appears to be a default on ARM64 Linux.
I think looking forward, one should anticipate long double being
128-bits rather than 80-bits.
I personally have not seen an extended FP format supported for a long time >{20 years)--yes, x86 still gives lip service to then, but "support is iffy" >at best.
For example, I have eXcel from 2003, and on AMD machines I get 80-bit precision (when real careful in eXcel math)--but those same programs
on Intel and Arm display 64-bit precision.
On Tue, 13 Oct 2026 21:33:23 GMT
MitchAlsup <[email protected]d> wrote:
For example, I have eXcel from 2003, and on AMD machines I get 80-bit precision (when real careful in eXcel math)--but those same programs
on Intel and Arm display 64-bit precision.
Are you sure that you use exactly the same version of Excel on AMD
and Intel? Also, what OS do you have on each machine?
Also, how exactly do you detect that precision is higher than IEEE
binary64? By forcing mantisa to hold more than 53 bits (incl.hidden) or
by forcing exponent to hold more than 11 bits?
Michael S <[email protected]> posted:
On Tue, 13 Oct 2026 21:33:23 GMT
MitchAlsup <[email protected]d> wrote:
For example, I have eXcel from 2003, and on AMD machines I get
80-bit precision (when real careful in eXcel math)--but those
same programs on Intel and Arm display 64-bit precision.
Are you sure that you use exactly the same version of Excel on AMD
and Intel? Also, what OS do you have on each machine?
Also, how exactly do you detect that precision is higher than IEEE binary64? By forcing mantisa to hold more than 53 bits
(incl.hidden) or by forcing exponent to hold more than 11 bits?
Very carefully crafted arithmetic. I calculated the Chebyshev points
on a 128-bit FP machine and then transported the ASCII data back and
gained 1.2ULP instead of calculating them using COS( point/k ) which
is the standard formula.
Also, instead of calculating a bunch of terms in multiple cells, I use SUMPRODUCT() which I found to be ~0.3ULP better than writing the
equations out by hand.
I have no idea why, just that I can measure {LOG(ABS(value),2)} as the
number of bits of precision--where value is the {AMD,Intel} builtin
minus my Chebyshev polynomial evaluated at the same point. Given 1,000 evaluations points between [a, b] with random dither at each point
the shape of the graph shows the accuracy while the noise on the graph
shows the arithmetic noise.
On Wed, 14 Oct 2026 22:13:04 GMT
MitchAlsup <[email protected]d> wrote:
Michael S <[email protected]> posted:
On Tue, 13 Oct 2026 21:33:23 GMT
MitchAlsup <[email protected]d> wrote:
For example, I have eXcel from 2003, and on AMD machines I get
80-bit precision (when real careful in eXcel math)--but those
same programs on Intel and Arm display 64-bit precision.
Are you sure that you use exactly the same version of Excel on AMD
and Intel? Also, what OS do you have on each machine?
Also, how exactly do you detect that precision is higher than IEEE binary64? By forcing mantisa to hold more than 53 bits
(incl.hidden) or by forcing exponent to hold more than 11 bits?
Very carefully crafted arithmetic. I calculated the Chebyshev points
on a 128-bit FP machine and then transported the ASCII data back and
gained 1.2ULP instead of calculating them using COS( point/k ) which
is the standard formula.
Also, instead of calculating a bunch of terms in multiple cells, I use SUMPRODUCT() which I found to be ~0.3ULP better than writing the
equations out by hand.
I have no idea why, just that I can measure {LOG(ABS(value),2)} as the number of bits of precision--where value is the {AMD,Intel} builtin
minus my Chebyshev polynomial evaluated at the same point. Given 1,000 evaluations points between [a, b] with random dither at each point
the shape of the graph shows the accuracy while the noise on the graph shows the arithmetic noise.
All that sounds non-trivial. The difference can be easily related to something else, e.g. to results of evaluation of trigs. Which do differ
a little between AMD and Intel.
What about trivial tests?
A = 1; B = A + 1e-18; C = B - 1;
| Sysop: | DaiTengu |
|---|---|
| Location: | Appleton, WI |
| Users: | 1,142 |
| Nodes: | 10 (0 / 10) |
| Uptime: | 93:07:32 |
| Calls: | 14,704 |
| Calls today: | 2 |
| Files: | 186,497 |
| D/L today: |
2,349 files (779M bytes) |
| Messages: | 2,551,657 |