
On Fri, Mar 18, 2022 at 11:16:47PM -0500, Tim Peters wrote:
[Steven D'Aprano <steve@pearwood.info>[\
Alas, math.remainder goes through float:
math.remainder(3**500, 3) # Should be 0. 1.0 math.remainder(3**500 + 2, 3) # Should be 2. 1.0
You mean -1 here: remainder() returns a member of the equivalence class with least absolute value, and abs(-1) < abs(2).
Correction noted. You said that before, and I skimmed over it. Sorry.
It would be nice if remainder() worked properly for exact values, without overflow or rounding errors.
I don't think so, It's required by 754-like standards explicitly for floating-point values. In that way, it's much too like math.fmod:
Sure, for floats. I certainly wouldn't want to change the behaviour for floats. We could change the behaviour for ints (or at least we could if not constrained by backwards compatibility) or add a new function. I was thinking more of Julia's rem(), which uses the sign of the dividend rather than the divisor. Speaking of which, Julia gives the correct result with no rounding error, but you have to declare your intermediate results as BigInts: julia> rem(big"3"^500, 3) 0
import math math.fmod(10**300, 100) 60.0
That's intended.
"Intended" is a little strong. I don't think that anyone set out to design a numeric system where an exact multiple of 100 gives a remainder of 60 when divided by 100 :-) Its more of an unavoidable consequence of other decisions, such as the use of base-2 rather than decimal, and limiting floats to 64 bits.
I don't know whether this counts as compelling or not, but I have a divmod variant which returns an always positive modulus for use in base conversion. It is only used in one place in a module I haven't touched in a decade, so it is quite possible that if I were writing that code again today, I wouldn't do it that way.
Insufficient information to guess from here. If; you're mucking around with negative bases,
Have you been spying on me again??? :-) -- Steve