Skip to content

Rounding

The round() built-in function takes an optional second argument. From a typing perspective, round() has two overloads, one with 1 parameter, and one with two. For both overloads, optype provides separate operand interfaces: CanRound1[R] and CanRound2[T, RT]. Additionally, optype also provides their (overloaded) intersection type: CanRound[-T, +R1, +R2] = CanRound1[R1] & CanRound2[T, R2].

operator operand
expression function type method type
round(_) do_round/1 DoesRound __round__/1 CanRound1[+R=int]
round(_, n) do_round/2 DoesRound __round__/2 CanRound2[-T=int, +R=float]
round(_, n=...) do_round DoesRound __round__ CanRound[-T=int, +R1=int, +R2=float]

For example, type-checkers will mark the following code as valid (tested with pyright in strict mode):

x: float = 3.14
x1: CanRound1[int] = x
x2: CanRound2[int, float] = x
x3: CanRound[int, int, float] = x

Furthermore, there are the alternative rounding functions from the math standard library:

operator operand
expression function type method type
math.trunc(_) do_trunc DoesTrunc __trunc__ CanTrunc[+R=int]
math.floor(_) do_floor DoesFloor __floor__ CanFloor[+R=int]
math.ceil(_) do_ceil DoesCeil __ceil__ CanCeil[+R=int]

Almost all implementations use int for R. In fact, if no type for R is specified, it will default in int. But technically speaking, these methods can be made to return anything.