You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Have math.isnormal() and, perhaps, math.issubnormal()? #132908
Of course, these functions can be emulated in pure-Python.
On another hand, people can reasonably expect these classifiers as "The math module consists mostly of thin wrappers around the platform C math library functions." (c) isnormal() was in libm since C99 and issubnormal() - since C23.
Has this already been discussed elsewhere?
This is a minor feature, which does not need previous discussion elsewhere
I once needed to know about whether a number is subnormal() so I would be happy to have it but... I think it's niche and numpy already proposes finfo for that so... I think users can live with this (big!) dependency if they already work with normal and subnormal numbers.
For isnormal(), if it's part of C99, I'd say why not because we're a "thin wrapper" but for issubnormal(), it'd be only available on platforms that compiled Python with C23 (unless you want to rewrite issubnormal()?)
I suggest leaving these out until there is a demonstrated user need.
Unless people actually need this (I never have), it becomes module clutter than gets in the way of finding "the good stuff". We shouldn't add cognitive loads (one more thing to learn and remember) unless we expect a payoff.
Contrary to closing it, I'd like to see it expanded to include fpclassify() too :smile. The math module always intended to be a superset of the standard C libm functions, and C has grown, and math has generally kept up with it (albeit with a lag).
Alas, it looks like although "even Microsoft" supports isnormal() and fpclassify() now, 'issubnormal()` appears to be missing.
I don't find Raymond's objection persuasive in this case. It's not like we're making them up - they're very widely implemented already (comes with being part of standard C), the names are bizarre enough that if's dead easy to find detailed docs with a web search, and they're not at all hard to understand. Indeed, the names are darned near self-explanatory
Ironically, I would have used these things yesterday, while writing a saner ldexp() for Windows. Instead I mucked around with frexp() to pick out the exponent to compare it with magical constants.
Which I appreciate is more in the area of writing math libraries than end-user apps. I don't think they'll be widely used. But there's another kind of cognitive burden in trying to remember which near-universally supported math functions Python thinks are beneath its attention 😉.
I'd like to see it expanded to include fpclassify()
I was thinking about, but I don't see good arguments beyond "libm has it". After all, we don't have every math.h's functions exposed in the module (e.g. scalbn or logb).
"even Microsoft" supports isnormal() and fpclassify() now, 'issubnormal()` appears to be missing.
issubnormal() is a part of C23, which MSVC doesn't support yet.
The C99+ Annex G doesn't define anything like that.
Though, it also doesn't include isfinite (or isinf/isnan). But it says:
A complex or imaginary value with at least one infinite part is regarded as an infinity (even if its
other part is a NaN). A complex or imaginary value is a finite number if each of its parts is a finite
number (neither infinite nor NaN).
That's exactly - Python's isfinite/isinf. The isnan() in Python looks as an extension. But I doubt that isnormal() for complex numbers can be defined like that.
Great, different programming languages disagree on this:
.NET:
publicstaticboolIsNormal(Complexvalue){// much as IsFinite requires both part to be finite, we require both// part to be "normal" (finite, non-zero, and non-subnormal) to be truereturndouble.IsNormal(value.m_real)&&((value.m_imaginary==0.0)||double.IsNormal(value.m_imaginary));}publicstaticboolIsSubnormal(Complexvalue){// much as IsInfinite allows either part to be infinite, we allow either// part to be "subnormal" (finite, non-zero, and non-normal) to be truereturndouble.IsSubnormal(value.m_real)||double.IsSubnormal(value.m_imaginary);}
Swift:
/// True if this value is normal.
///
/// A complex number is normal if it is finite and *either* the real or
/// imaginary component is normal. A floating-point number representing
/// one of the components is normal if its exponent allows a full-precision
/// representation.
///
/// See also `.isFinite`, `.isSubnormal` and `.isZero`.
@_transparentpublicvarisNormal:Bool{
isFinite && (x.isNormal || y.isNormal)}
/// True if this value is subnormal.
///
/// A complex number is subnormal if it is finite, not normal, and not zero.
/// When the result of a computation is subnormal, underflow has occurred and
/// the result generally does not have full precision.
///
/// See also `.isFinite`, `.isNormal` and `.isZero`.
@_transparentpublicvarisSubnormal:Bool{
isFinite && !isNormal && !isZero
}
No doubts, you can define such notions. But note, that your definitions are different.
The C99 standard rationale shows arguments for isinf/isnan, e.g.:
Which arguments for using either definition of isnormal() for complex numbers? Is this useful? Why? M$ version is especially odd as asymmetrical wrt components.
isnormal(z) = isnormal(z.real) and isnormal(z.imag):
performance:
$ python -m timeit -s "a = 2+0j; b = 5e-308+5e-308j""a * b"
5000000 loops, best of 5: 49.1 nsec per loop
$ python -m timeit -s "a = 2+0j; b = 5e-308+5e-324j""a * b"
5000000 loops, best of 5: 88.3 nsec per loop
$ python -m timeit -s "a = 2+0j; b = 5e-324+5e-324j""a * b"
2000000 loops, best of 5: 124 nsec per loop
Do you see an argument for the other definition? Or should we give that a different name? isnormal(z) = isfinite(z) and (isnormal(z.real) or isnormal(z.imag))
I'm mostly trying to compare it with the reasons for having std::isnormal(x).
Most CPU's handle subnormal numbers much more slowly than normals. A simple multipliction by 2, can be up to 2.53x slower (compared to 1.15x slower for infinities). I expect a similar story for other operations.
When you get a subnormal number after multiplication, you lose precision in later operations.
So, raising an error in these cases using isnormal() could make sense.
Activity
picnixz commentedon Apr 25, 2025
I once needed to know about whether a number is subnormal() so I would be happy to have it but... I think it's niche and
numpyalready proposesfinfofor that so... I think users can live with this (big!) dependency if they already work with normal and subnormal numbers.For
isnormal(), if it's part of C99, I'd say why not because we're a "thin wrapper" but forissubnormal(), it'd be only available on platforms that compiled Python with C23 (unless you want to rewriteissubnormal()?)skirpichev commentedon Apr 25, 2025
This is something more basic and is a part of libm.
Yes, it's essentially a free lunch.
I think we can check compiler conformance and if C23 support is missing - provide a simple replacement in terms of isfinite() & isnormal().
pythongh-132908: add math.normal/subnormal() functions
skirpichev commentedon Apr 25, 2025
PR is ready to review: #132935
rhettinger commentedon Apr 25, 2025
I suggest leaving these out until there is a demonstrated user need.
Unless people actually need this (I never have), it becomes module clutter than gets in the way of finding "the good stuff". We shouldn't add cognitive loads (one more thing to learn and remember) unless we expect a payoff.
skirpichev commentedon Apr 25, 2025
If bugreport is a demonstration of "used needs" - here it is.
SO example: https://stackoverflow.com/questions/59277521
On the other hand, people can expect this from the libm wrapper. This time, rather than reinventing the wheel - I filled this bugreport.
skirpichev commentedon Apr 28, 2025
I'm going to close this, on ground of Raymond's feedback.
@tim-one ?
tim-one commentedon Apr 28, 2025
Contrary to closing it, I'd like to see it expanded to include
fpclassify()too :smile. Themathmodule always intended to be a superset of the standard Clibmfunctions, and C has grown, andmathhas generally kept up with it (albeit with a lag).Alas, it looks like although "even Microsoft" supports
isnormal()andfpclassify()now, 'issubnormal()` appears to be missing.I don't find Raymond's objection persuasive in this case. It's not like we're making them up - they're very widely implemented already (comes with being part of standard C), the names are bizarre enough that if's dead easy to find detailed docs with a web search, and they're not at all hard to understand. Indeed, the names are darned near self-explanatory
Ironically, I would have used these things yesterday, while writing a saner
ldexp()for Windows. Instead I mucked around withfrexp()to pick out the exponent to compare it with magical constants.Which I appreciate is more in the area of writing math libraries than end-user apps. I don't think they'll be widely used. But there's another kind of cognitive burden in trying to remember which near-universally supported math functions Python thinks are beneath its attention 😉.
skirpichev commentedon May 1, 2025
I was thinking about, but I don't see good arguments beyond "libm has it". After all, we don't have every
math.h's functions exposed in the module (e.g. scalbn or logb).issubnormal() is a part of C23, which MSVC doesn't support yet.
2 remaining items
gh-132908: Add math.isnormal/issubnormal() functions (GH132935)
nineteendo commentedon Jun 6, 2025
Aren't we missing
cmath.isnormal()andcmath.issubnormal()?isnormal(z): Check if ALL components of z are normalissubnormal(z): Check if ANY component of z is subnormalskirpichev commentedon Jun 6, 2025
The C99+ Annex G doesn't define anything like that.
Though, it also doesn't include isfinite (or isinf/isnan). But it says:
That's exactly - Python's isfinite/isinf. The isnan() in Python looks as an extension. But I doubt that isnormal() for complex numbers can be defined like that.
nineteendo commentedon Jun 6, 2025
Great, different programming languages disagree on this:
skirpichev commentedon Jun 7, 2025
No doubts, you can define such notions. But note, that your definitions are different.
The C99 standard rationale shows arguments for isinf/isnan, e.g.:
Which arguments for using either definition of isnormal() for complex numbers? Is this useful? Why? M$ version is especially odd as asymmetrical wrt components.
nineteendo commentedon Jun 7, 2025
isnormal(z) = isnormal(z.real) and isnormal(z.imag):Do you see an argument for the other definition? Or should we give that a different name?
isnormal(z) = isfinite(z) and (isnormal(z.real) or isnormal(z.imag))skirpichev commentedon Jun 7, 2025
Sorry, could be elaborate your "performance" and "accuracy" arguments?
nineteendo commentedon Jun 7, 2025
I'm mostly trying to compare it with the reasons for having
std::isnormal(x).So, raising an error in these cases using
isnormal()could make sense.skirpichev commentedon Jun 7, 2025
Yes, but I don't see yet arguments for a concrete
isnormal()definition for complex.nineteendo commentedon Jun 7, 2025
Maybe we should discuss this on Discourse?
skirpichev commentedon Jun 7, 2025
Feel free to do so .
I'm not sure if it worth, I am -0 on this.
pythongh-132908: Add math.isnormal/issubnormal() functions (GH132935)
pythongh-132908: Add math.isnormal/issubnormal() functions (GH132935)
pythongh-132908: Add math.isnormal/issubnormal() functions (GH132935)