Skip to content

Numbers

This page shows how numbers behave in d/Python. Whole numbers (integers) work exactly as they do in Python: they can be as large as you like, and division, remainders, powers and bit operations all give Python's answers. Decimal numbers (floats) are only partly there, and the Floats section says exactly what works and what does not yet. After reading this page you will know which arithmetic you can rely on today.

The integer code lives in a shared support library that the compiler links into your program only when the program needs it. Every operation on this page is checked against the reference CPython build (3.9.6) that every d/Python test is compared with.

Integers grow with the result

There is no fixed upper size. A result simply grows as large as it needs to be.

print(2 ** 100)
print(10 ** 30 + 1)
print(1 << 70, -256 >> 4)
value = 1
for i in range(1, 31):
    value *= i
print(value)

Division rounds down, the remainder takes the divisor's sign

print(7 // 2, -7 // 2, 7 // -2)
print(7 % 2, -7 % 2, 7 % -2)
print(divmod(-7, 2), divmod(7, -2))
try:
    print(1 // 0)
except ZeroDivisionError as error:
    print("caught:", error)

Dividing by zero raises ZeroDivisionError, an ordinary Python exception that you can catch, with the same message CPython prints. Ordinary division with / produces a float, and floats are not yet supported: the compiler stops at that line and tells you so. See the float boundary below.

Powers

print(pow(2, 100))
print(pow(7, 1000000000000000000000123, 97))
print(pow(7, 13, -19), pow(2, 10, None))
print(3 ** 4, (-2) ** 3, 2 ** 0)

** and two-argument pow take an exponent of zero or more. Three-argument pow(base, exponent, modulus) takes a positive or negative modulus that is not zero, and it reduces the result at every step, so a huge exponent with a small modulus stays small and fast. A modulus of 1 or -1 gives 0. A negative exponent would need either a float result or a modular inverse, and neither is supported yet: the program raises NotImplementedError at that point, and the message says which piece is missing.

Bits

print(5 & 3, 5 | 3, 5 ^ 3, ~5)
print(bin(-10), oct(8), hex(255))
print(True & True, True | False, True ^ True)

Bit operations on negative numbers behave as in Python, where a negative number acts as if it had an endless run of one bits on the left. &, | and ^ on two booleans give a boolean, as in Python. Shifting by a negative count is an error, and a right shift by an enormous count works correctly instead of the count being cut down to a smaller number. bin, oct and hex keep their prefixes and the minus sign for any integer.

Conversions

print(int("42"), int("-0x1f", 16), int("1_000"), int("  12  "), int(b"7"))
print(int("١٢٣"), int("z", 36), int(True), int(False))
try:
    int("x1")
except ValueError as error:
    print("ValueError:", error)
print(str(2 ** 64), repr(-1), abs(-3), bool(0), bool(7))

int() reads text and bytes in any base from 2 to 36, or base 0, which reads the prefix to choose the base. It accepts a sign, underscores between digits, surrounding spaces, and digits from any script that Unicode counts as decimal. Text that is not a number raises ValueError, which you can catch. Converting a float to an integer, and converting objects of your own classes to integers, are not yet supported.

Booleans are integers

True counts as 1 and False as 0 wherever arithmetic asks for a number, as in Python.

print(True + True, True * 3, sum([True, False, True]))
print(3 > 2 > 1, 1 < 2 < 3 < 4, True == 1)

Reductions

print(sum(range(101)), sum([1, 2, 3], 10))
print(min(3, 1, 2), max([4, 9, 2]), min([], default=0))
print(sorted([3, -1, 2], key=abs), max(["pear", "fig"], key=len))

sum adds up numbers or a list of numbers, with an optional starting value. min and max take several arguments or one collection, accept a default for an empty collection, and accept a key function, which may be a closure or an object with a __call__ method. When two items tie, the first one wins, as in Python.

Floats

Floats are Python's 64-bit floats, and they behave the way Python's do: 7 / 2 is 3.5, 0.1 + 0.2 prints 0.30000000000000004, round rounds a tie to the even neighbour, and float("nan") is not equal to itself. Printing and formatting use the shortest text that reads back to the same number, as CPython does.

print(7 / 2, -7.0 % 2, 0.1 + 0.2, 2 ** 0.5)
print(float("1.5"), float(" -2.5e3 "), float(True), int(-2.75))
print(round(2.5), round(3.5), round(2.675, 2), round(1450, -2))
print(1e300 * 10, float("inf") > 10 ** 400, float("nan") != float("nan"))
print(9007199254740993 > 9007199254740992.0)
print((0.1).as_integer_ratio(), (2.5).is_integer(), float.fromhex("0x1.8p1"))
try:
    float(10 ** 400)
except OverflowError as error:
    print("OverflowError:", error)

A few things worth knowing. Comparing an integer with a float compares the exact integer, so a 16-digit integer is not silently rounded first. Converting a huge integer to a float raises OverflowError, and converting nan or inf to an integer raises the Python errors. Complex numbers work too: complex(1, 2) * complex(3, 4) is (-5+10j), with abs, powers and .conjugate().

print(f"{3.14159:.2f} | {42:>6} | {1234567:,} | {255:#x} | {0.5:.0%}")
print(format(12345.625, ",.2f"), format(7, "03d"), format(-1.5, "+.1f"))
print(pow(2, -3), pow(3, -1, 11), divmod(7.5, 2))

Format specifications work in f-strings and format(): sign, alignment, fill, width, precision, grouping and the alternate form. % formatting and str.format are not yet supported.

Classes can take part: an ordinary __float__, __int__, __index__, __round__ or __abs__ method on your class is used by the matching builtin. Single-inheritance subclasses of int, float and complex keep their identity and fields. Still to come are custom binary operators on your own classes (__add__, __eq__ and friends), which the compatibility table tracks. The console_numbers example in the playground exercises most of this page.

What the tests cover

Every claim on this page comes from a test program that runs in both d/Python and CPython and must print the same thing. The corpus page lists those programs, from arithmetic and divmod through bit operations, conversions and reductions, each with its reviewed output and its result in this browser build.