Skip to main content

Objects/floatobject.c

Map

LinesSymbolRolegopy
1–30PyFloatObjectStruct: single double ob_fval fieldobjects.Float
132–171PyFloat_FromDoubleAllocate a float from a C double; uses free-listobjects.NewFloat
172–280PyFloat_FromStringParse a Python literal via _Py_dg_strtod, PEP 515 underscoresobjects.FloatFromString
255–270PyFloat_AsDoubleUnwrap to C double, raise TypeError on non-float(*Float).Float64
600–700float_hashConsistent with int hash modulo Mersenne prime 2^61-1objects.floatHash
730–820float_richcompareFull IEEE comparison including NaN short-circuitobjects.floatRichCmp
900–1000float_as_integer_ratioReturns exact (numerator, denominator) tuplenot yet ported
1265–1400PyOS_double_to_stringShortest-roundtrip repr via _Py_dg_dtoaobjects.formatFloatShort
1800–1870float_freelist_push/popFree-list cache up to 256 float objectsnot ported (GC handled by Go)
2068PyFloat_TypeType singleton wiring all slotsobjects.FloatType

Reading

Object layout

holds exactly one field: double ob_fval. There are no variant representations. The gopy mirror objects.Float wraps a Go float64 named v inside a struct that also embeds Header for the type pointer and reference bookkeeping.

The free-list (float_freelist_push / float_freelist_pop) recycles up to 256 dead float cells. gopy omits this because Go's garbage collector handles allocation churn without a manual slab.

Construction and parsing

is the primitive constructor. builds on top of it: it strips whitespace, handles an optional sign, dispatches inf/infinity/nan tokens case-insensitively via , removes PEP 515 underscores, then calls _Py_dg_strtod for the digit-to-double conversion. gopy replaces _Py_dg_strtod with Go's strconv.ParseFloat, which uses the same shortest-roundtrip (Ryu / Grisu) algorithm internally.

Hash consistency

Python enforces hash(x) == hash(int(x)) for any float x that is an exact integer. achieves this by computing the hash modulo the Mersenne prime 2^61-1, the same modulus used for int. When the float is non-integral the hash is derived directly from the IEEE bit pattern, then adjusted so the value -1 is never returned (CPython reserves -1 as the error sentinel). objects.floatHash mirrors this logic and delegates to intHash for the integral fast path.

Repr and richcompare

with flags 'r' and Py_DTSF_ADD_DOT_0 produces the shortest decimal string that round-trips back to the same double, then chooses between fixed (ddd.ddd) and exponential (d.ddde+NN) layout: exponent form is used when the decimal-point position is <= -4 or > 16. objects.formatFloatShort replicates the layout decision by going through strconv.FormatFloat('e') first to extract the mantissa digits and exponent, then re-formatting.

float_richcompare handles the NaN case by returning NotImplemented for ordered comparisons (<, <=, >, >=) when either operand is NaN, so nan != nan is True and all other comparisons are False. objects.floatRichCmp delegates to Go's native float comparison operators which already have correct IEEE-754 NaN semantics.

gopy mirror

The port lives across two files:

  • /objects/float.go covers PyFloat_FromDouble, PyFloat_AsDouble, all arithmetic slots, float_hash, and float_richcompare.
  • /objects/float_parse.go covers PyFloat_FromString, _Py_parse_inf_or_nan, and the underscore-stripping helper.

float_as_integer_ratio and PyFloat_GetInfo are not yet ported. The free-list is intentionally omitted; Go's allocator makes it unnecessary.