Smallest float different from 0.0?

K

kj

Is there some standardized way (e.g. some "official" module of such
limit constants) to get the smallest positive float that Python
will regard as distinct from 0.0?

TIA!

kj
 
P

Paul McGuire

Is there some standardized way (e.g. some "official" module of such
limit constants) to get the smallest positive float that Python
will regard as distinct from 0.0?

TIA!

kj

You could find it for yourself:
.... if 10**-i == 0:
.... print i
.... break
....
324

-- Paul
 
D

Diez B. Roggisch

Paul said:
You could find it for yourself:

... if 10**-i == 0:
... print i
... break
...
324


I think this is even a bit closer:

for i in xrange(10000):
try:
v = 1 / (2**-i)
except ZeroDivisionError:
print i, v
break

-> 1075

If you test the inverse (10 ** 324 and 2 ** 1075) you see that the binary
variant is 4.something * 10 ** 323.

Diez
 
M

Mark Dickinson

Is there some standardized way (e.g. some "official" module of such
limit constants) to get the smallest positive float that Python
will regard as distinct from 0.0?

TIA!

kj

There's sys.float_info.min:
sys.float_info(max=1.7976931348623157e+308, max_exp=1024,
max_10_exp=308, min=2.2250738585072014e-308, min_exp=-1021,
min_10_exp=-307, dig=15, mant_dig=53, epsilon=2.2204460492503131e-16,
radix=2, rounds=1)2.2250738585072014e-308

But that only gives you the smallest *normal* positive float, which
is 2**-1022 on most systems. The smallest positive subnormal value
is usually 2**-1074. If you want something that would still work
if Python ever switched to using IEEE 754 binary128 format (or some
other IEEE 754 format), then

sys.float_info.min * 2**(1-sys.float_info.mant_dig)

will work.

But on 99.99%+ of systems you'll find Python running on, it's going
to be 2**-1074.

Mark
 
K

kj

There's sys.float_info.min:

Ah! I'd seen sys.float_info when searched for this online, but
incorrectly inferred that it was the name of a module.

This is what I was looking for.

Thanks!

kynn
 
K

kj

In said:
The smallest positive subnormal value
is usually 2**-1074. If you want something that would still work
if Python ever switched to using IEEE 754 binary128 format (or some
other IEEE 754 format), then
sys.float_info.min * 2**(1-sys.float_info.mant_dig)

Hmmm. This close-to-the-metal IEEE stuff make a "HERE BE DRAGONS!"
alarms go off in my head... (What's up with that correction by 1
to sys.float_info.mant_dig? Or, probably equivalently, why would
sys.float_info.min_exp (-1021) be off by 1 relative to log2 of
sys.float_info.min (-1022)?)

I suppose that

2**(sys.float_info.min_exp - sys.float_info.mant_dig)

would also work?

I must confess, this stuff is way beyond me... I'm glad that
sys.float_info is available...

kynn
 
M

Mark Dickinson

Hmmm.  This close-to-the-metal IEEE stuff make a "HERE BE DRAGONS!"
alarms go off in my head...  (What's up with that correction by 1
to sys.float_info.mant_dig?  Or, probably equivalently, why would
sys.float_info.min_exp (-1021) be off by 1 relative to log2 of
sys.float_info.min (-1022)?)

The sys.float_info constants come straight from the standard C
limits defined in float.h. The C standards choose to describe
floats in the form

sign * 2**exponent * significand

with 0.5 <= significand < 1.0. (Well, assuming base 2; the
actual standard is a bit more general than this; see e.g.
section 5.2.4.2.2 of C99.)

So from C's point of view, the smallest normal value
comes from the minimum exponent (-1021) together with
the minimum significand (0.5), so it's 2**-1021 * 0.5,
or 2**-1022. Similarly, the max value is (1-2**-53)*2**1024.

It's a bit unfortunate that the IEEE 754 standard prefers
a different normalization, with the exponent chosen so that
the significand is in [1.0, 2.0). So where IEEE 754-2008
gives emax as 1023, C gives DBL_MAX_EXP as 1024; both
describing exactly the same format.
I suppose that

2**(sys.float_info.min_exp - sys.float_info.mant_dig)

would also work?

Yes. This all only works for IEEE 754 binary formats,
though. Most other floating-point formats you're likely
to meet (IBM hex floats, VAX D and G, Cray floats, etc.)
don't have gradual underflow and subnormals.
 
S

Steven D'Aprano

There's sys.float_info.min: ....
But that only gives you the smallest *normal* positive float, which is
2**-1022 on most systems.

The IEEE standard mandates a "nextafter" function which takes a float as
an argument, and returns the next greater float. Tim Peters gave an
implementation here:

http://mail.python.org/pipermail/python-list/2001-August/099152.html

Unfortunately, it doesn't work for negative floats, zero or denormalised
floats.
 
S

Steven D'Aprano

There's sys.float_info.min:

sys.float_info(max=1.7976931348623157e+308, max_exp=1024,
max_10_exp=308, min=2.2250738585072014e-308, min_exp=-1021,
min_10_exp=-307, dig=15, mant_dig=53, epsilon=2.2204460492503131e-16,
radix=2, rounds=1)
2.2250738585072014e-308

But that only gives you the smallest *normal* positive float, which is
2**-1022 on most systems. The smallest positive subnormal value is
usually 2**-1074. If you want something that would still work if Python
ever switched to using IEEE 754 binary128 format (or some other IEEE 754
format), then

sys.float_info.min * 2**(1-sys.float_info.mant_dig)

will work.


Here's another implementation to give the next float. It should work for
"normal" binary implementations:

from struct import pack, unpack

def next(x, y=None):
"""Returns the next float from x in the direction of y.
If y is not given, the direction is towards positive infinity.
"""
if x == y:
return x
if y is None or y > x:
delta = cmp(x, 0.0) or 1
elif y < x:
delta = -(cmp(x, 0.0) or 1)
else:
raise ValueError("unordered x, y: %f, %f" % (x, y))
return unpack('d', pack('q', unpack('q', pack('d', x))[0]+delta))[0]


nan


You can also get signed zero:
-0.0
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
474,197
Messages
2,571,040
Members
47,635
Latest member
SkyePurves

Latest Threads

Top