quad-fp:   quadruple-precision floating point
1 Accuracy
2 Performance
3 Datatype
Quad-Flonum
Quad?
4 Conversion
double-flonum->quad-flonum
quad-flonum->double-flonum
string->quad-flonum
quad-flonum->string
quad-flonum->bytes
5 Arithmetic
qf+
qf-
qf*
qf/
6 Elementary functions
qfabs
qfsqrt
qfcbrt
qfpow
qfhypot
qfexp
qfexp2
qfexpm1
qflog
qflog2
qflog10
qflog1p
qfsin
qfcos
qftan
qfasin
qfacos
qfatan
qfatan2
qfsinh
qfcosh
qftanh
qfasinh
qfacosh
qfatanh
7 Rounding
qfceil
qffloor
qftrunc
qfround
qfrint
qfnearbyint
8 Special functions
qferf
qferfc
qflgamma
qftgamma
qfj0
qfj1
qfy0
qfy1
9 Other binary functions
qffmod
qfremainder
qfcopysign
qffdim
qfmax
qfmin
qfnextafter
qffma
10 Comparison
qf=
qf<
qf<=
qf>
qf>=
11 Classification
qfnan?
qfinfinite?
qffinite?
qfsignbit?
12 Constants
quad-pi
quad-pi/  2
quad-pi/  4
quad-1/  pi
quad-2/  pi
quad-2/  sqrt-pi
quad-e
quad-log2e
quad-log10e
quad-ln2
quad-ln10
quad-sqrt2
quad-1/  sqrt2
quad-max
quad-min
quad-epsilon
quad-denorm-min
quad-mant-dig
quad-decimal-dig
quad-min-exp
quad-max-exp
quad-min-10-exp
quad-max-10-exp
9.2

quad-fp: quadruple-precision floating point🔗ℹ

Shaobo He

 (require quad-fp) package: quad-fp

A toy Racket FFI binding to GCC’s libquadmath, exposing IEEE 754 quadruple-precision (128-bit, __float128) floating point — roughly 34 significant decimal digits, versus the ~16 of Racket’s native double flonums.

Values are opaque: a quad is shuttled across the FFI boundary as 128 bits and is only ever produced or consumed by the operations below. The qf… operations mirror libquadmath’s …q C functions — qfsqrt wraps sqrtq, qffma wraps fmaq, and so on — so libquadmath’s own documentation maps directly onto this API.

(require quad-fp)
(define a (double-flonum->quad-flonum 1.0))
(define b (double-flonum->quad-flonum 1e-20))
; In double, 1.0 + 1e-20 == 1.0; in quad the addend survives:
(qf= (qf+ a b) a)
; => #f
(quad-flonum->string (qf* quad-pi quad-pi))
; => "9.86960440108935861883449099987615081"

The binding loads a native shared library (libquadf) that is compiled from source at install time, so a C toolchain with libquadmath must be present. See the package README for details.

1 Accuracy🔗ℹ

Every result comes straight from libquadmath, so the accuracy is libquadmath’s and varies slightly across GCC versions. The package’s property tests, which check each operation against math/bigfloat at 113-bit precision, characterize it as follows:

  • qf+, qf-, qf*, and qf/ are correctly rounded on every libquadmath: each result is the exact value rounded to the nearest binary128, matching math/bigfloat bit for bit.

  • qfsqrt and qffma are correctly rounded on recent libquadmath, but only faithfully rounded (within one unit in the last place) on older builds. There sqrtq refines a double seed by Newton’s method with no final correcting step, and fmaq may double-round by up to one ulp — while still computing a true, cancellation-safe fused multiply-add.

  • The transcendental and special functions are not guaranteed correctly rounded; in practice they are within a few ulps. The gamma functions qftgamma and qflgamma are the least accurate and vary the most from one libquadmath to the next.

A quad result may therefore differ in its last bit or two from one produced by another correctly-rounded library.

2 Performance🔗ℹ

Every operation crosses the Racket/C boundary and allocates its result — a fixed overhead of roughly 40–70 nanoseconds per call on x86-64, independent of the operation. The relative cost therefore depends on how much work the operation itself does. Arithmetic and qfabs are cheap in libquadmath (around 10 ns), so the boundary dominates: expect about 4–6× the cost of the same operation in C. qfsqrt and every transcendental or special function take hundreds to thousands of nanoseconds, leaving the boundary in the noise — within roughly 15%, and under 5% for the dearest ones such as qferf, qfpow, and qftgamma.

The pattern, measured on one x86-64 machine (gcc -O3, approximate ns per call):

operation

  

raw C

  

quad-fp/quadf

  

ratio

qfabs

  

7

  

38

  

5.5×

qf+

  

13

  

59

  

4.6×

qf*

  

14

  

65

  

4.6×

qf/

  

15

  

66

  

4.3×

qfsqrt

  

308

  

350

  

1.14×

qfsin

  

443

  

487

  

1.10×

qffma

  

469

  

540

  

1.15×

qfexp

  

549

  

591

  

1.08×

qferf

  

1212

  

1256

  

1.04×

qftgamma

  

2837

  

2899

  

1.02×

Absolute numbers are machine-dependent; the ratios are the portable part.

Those figures are for the untyped layer, quad-fp/quadf. The default quad-fp additionally wraps each export in the Typed Racket require/typed contract — another flat ~45 ns per call, a Quad? check on every argument and result. That roughly doubles the cheap arithmetic operations but is negligible for the expensive ones, and it applies to typed and untyped callers alike. Code that is bottlenecked on quad arithmetic and does not need the static types can (require quad-fp/quadf) to bypass it.

3 Datatype🔗ℹ

The type of quadruple-precision values. This package is implemented in Typed Racket, so in typed code every operation here consumes and produces Quad-Flonums. The type is opaque — a value is created only by a conversion (such as double-flonum->quad-flonum or string->quad-flonum) or a named constant, never written as a literal. The module is equally usable from untyped Racket, where Quad-Flonum does not appear and the predicate Quad? takes its place.

procedure

(Quad? v)  boolean?

  v : any/c
Returns #t if v is a Quad-Flonum produced by this library, #f otherwise — Quad-Flonum’s runtime counterpart, and the predicate the procedure signatures below are written against.

4 Conversion🔗ℹ

procedure

(double-flonum->quad-flonum x)  Quad?

  x : flonum?

procedure

(quad-flonum->double-flonum q)  flonum?

  q : Quad?
Convert between a Racket double flonum? and a quad. Widening a double is exact; narrowing back to a double rounds to nearest.

procedure

(string->quad-flonum s)  Quad?

  s : string?

procedure

(quad-flonum->string q [precision])  string?

  q : Quad?
  precision : exact-integer? = 36
Parse a decimal string into a quad (via strtoflt128), and render a quad to a decimal string with precision significant digits (via quadmath_snprintf). The default of 36 digits round-trips binary128 exactly.

procedure

(quad-flonum->bytes q)  bytes?

  q : Quad?
Returns the 16 bytes of q’s __float128 bit pattern, low 64-bit half first and each half in the platform’s native byte order — i.e. the value’s little-endian byte string on x86-64.

5 Arithmetic🔗ℹ

procedure

(qf+ a b)  Quad?

  a : Quad?
  b : Quad?

procedure

(qf- a b)  Quad?

  a : Quad?
  b : Quad?

procedure

(qf* a b)  Quad?

  a : Quad?
  b : Quad?

procedure

(qf/ a b)  Quad?

  a : Quad?
  b : Quad?
Quad-precision addition, subtraction, multiplication, and division.

6 Elementary functions🔗ℹ

procedure

(qfabs a)  Quad?

  a : Quad?

procedure

(qfsqrt a)  Quad?

  a : Quad?

procedure

(qfcbrt a)  Quad?

  a : Quad?

procedure

(qfpow a b)  Quad?

  a : Quad?
  b : Quad?

procedure

(qfhypot a b)  Quad?

  a : Quad?
  b : Quad?
Absolute value, square and cube roots, a raised to b, and (qfsqrt (qf+ (qf* a a) (qf* b b))) without overflow.

procedure

(qfexp a)  Quad?

  a : Quad?

procedure

(qfexp2 a)  Quad?

  a : Quad?

procedure

(qfexpm1 a)  Quad?

  a : Quad?

procedure

(qflog a)  Quad?

  a : Quad?

procedure

(qflog2 a)  Quad?

  a : Quad?

procedure

(qflog10 a)  Quad?

  a : Quad?

procedure

(qflog1p a)  Quad?

  a : Quad?
Exponentials (qfexpm1 computes ex-1 accurately near 0) and logarithms (qflog1p computes log(1+x)).

procedure

(qfsin a)  Quad?

  a : Quad?

procedure

(qfcos a)  Quad?

  a : Quad?

procedure

(qftan a)  Quad?

  a : Quad?

procedure

(qfasin a)  Quad?

  a : Quad?

procedure

(qfacos a)  Quad?

  a : Quad?

procedure

(qfatan a)  Quad?

  a : Quad?

procedure

(qfatan2 a b)  Quad?

  a : Quad?
  b : Quad?
Trigonometric functions and their inverses; qfatan2 is the two-argument arctangent.

procedure

(qfsinh a)  Quad?

  a : Quad?

procedure

(qfcosh a)  Quad?

  a : Quad?

procedure

(qftanh a)  Quad?

  a : Quad?

procedure

(qfasinh a)  Quad?

  a : Quad?

procedure

(qfacosh a)  Quad?

  a : Quad?

procedure

(qfatanh a)  Quad?

  a : Quad?
Hyperbolic functions and their inverses.

7 Rounding🔗ℹ

procedure

(qfceil a)  Quad?

  a : Quad?

procedure

(qffloor a)  Quad?

  a : Quad?

procedure

(qftrunc a)  Quad?

  a : Quad?

procedure

(qfround a)  Quad?

  a : Quad?

procedure

(qfrint a)  Quad?

  a : Quad?

procedure

(qfnearbyint a)  Quad?

  a : Quad?
Round toward +∞, -∞, zero, and nearest (ties away from zero for qfround; using the current rounding mode for qfrint and qfnearbyint).

8 Special functions🔗ℹ

procedure

(qferf a)  Quad?

  a : Quad?

procedure

(qferfc a)  Quad?

  a : Quad?

procedure

(qflgamma a)  Quad?

  a : Quad?

procedure

(qftgamma a)  Quad?

  a : Quad?

procedure

(qfj0 a)  Quad?

  a : Quad?

procedure

(qfj1 a)  Quad?

  a : Quad?

procedure

(qfy0 a)  Quad?

  a : Quad?

procedure

(qfy1 a)  Quad?

  a : Quad?
Error functions, log-gamma and gamma, and Bessel functions of the first (qfj0, qfj1) and second (qfy0, qfy1) kind, orders 0 and 1.

9 Other binary functions🔗ℹ

procedure

(qffmod a b)  Quad?

  a : Quad?
  b : Quad?

procedure

(qfremainder a b)  Quad?

  a : Quad?
  b : Quad?

procedure

(qfcopysign a b)  Quad?

  a : Quad?
  b : Quad?

procedure

(qffdim a b)  Quad?

  a : Quad?
  b : Quad?

procedure

(qfmax a b)  Quad?

  a : Quad?
  b : Quad?

procedure

(qfmin a b)  Quad?

  a : Quad?
  b : Quad?

procedure

(qfnextafter a b)  Quad?

  a : Quad?
  b : Quad?

procedure

(qffma a b c)  Quad?

  a : Quad?
  b : Quad?
  c : Quad?
Floating-point remainder, IEEE remainder, sign copying, positive difference, maximum, minimum, next representable value toward b, and the fused multiply-add (qf+ (qf* a b) c), computed with a single rounding where libquadmath provides it (see Accuracy).

10 Comparison🔗ℹ

procedure

(qf= a b)  boolean?

  a : Quad?
  b : Quad?

procedure

(qf< a b)  boolean?

  a : Quad?
  b : Quad?

procedure

(qf<= a b)  boolean?

  a : Quad?
  b : Quad?

procedure

(qf> a b)  boolean?

  a : Quad?
  b : Quad?

procedure

(qf>= a b)  boolean?

  a : Quad?
  b : Quad?
Quad-precision comparisons, returning Racket booleans.

11 Classification🔗ℹ

procedure

(qfnan? a)  boolean?

  a : Quad?

procedure

(qfinfinite? a)  boolean?

  a : Quad?

procedure

(qffinite? a)  boolean?

  a : Quad?

procedure

(qfsignbit? a)  boolean?

  a : Quad?
Test for NaN, infinity, finiteness, and a set sign bit.

12 Constants🔗ℹ

value

quad-pi : Quad?

value

quad-pi/2 : Quad?

value

quad-pi/4 : Quad?

value

quad-1/pi : Quad?

value

quad-2/pi : Quad?

value

quad-2/sqrt-pi : Quad?

value

quad-e : Quad?

value

quad-log2e : Quad?

value

quad-log10e : Quad?

value

quad-ln2 : Quad?

value

quad-ln10 : Quad?

value

quad-sqrt2 : Quad?

value

quad-1/sqrt2 : Quad?

The mathematical constants from libquadmath’s M_*q macros (π, π/2, π/4, 1/π, 2/π, 2/√π, e, log₂e, log₁₀e, ln 2, ln 10, √2, 1/√2).

Largest finite, smallest positive normal, machine epsilon, and smallest positive subnormal (FLT128_MAX, FLT128_MIN, FLT128_EPSILON, FLT128_DENORM_MIN).

Format characteristics: mantissa bits (113), round-trippable decimal digits (33), and the binary and decimal exponent ranges.