python - Convert numpy float to string - Stack Overflow
import numpy as np
number = np.float32(0.12345678)
assert str(number) == "0.12345678"
assert f"{number}" == "0.12345678359270096"
Why is this different when converting a numpy float to string using str
built-in function and f-string?
import numpy as np
number = np.float32(0.12345678)
assert str(number) == "0.12345678"
assert f"{number}" == "0.12345678359270096"
Why is this different when converting a numpy float to string using str
built-in function and f-string?
- If you feel the answer below doesn't answer the specific question you had about these, please feel free to comment on it to ask for clarification. – Grismar Commented 19 hours ago
1 Answer
Reset to default 5As pointed out in the comments, the first part of the answer would be to point out that f-string representations are often different from str()
outcomes.
However, that leaves the question "why does __format__
result in more digits being rendered than __str__
for a numpy.float32
?"
Have a look at this:
import numpy as np
x = np.float32(0.12345678)
print('np.float32 __str__ method return value:', x.__str__())
print('np.float32 __repr__ method return value:', x.__repr__())
print('np.float32 __format__ method return value with "f":', x.__format__('f'))
print('np.float32 formatted by an f-string:', f'{x}')
print('float __str__ method return value:', float(x).__str__())
print('float __repr__ method return value:', float(x).__repr__())
print('float __format__ method return value with "f":', float(x).__format__('f'))
print('float formatted by an f-string:', f'{float(x)}')
Output:
np.float32 __str__ method return value: 0.12345678
np.float32 __repr__ method return value: 0.12345678
np.float32 __format__ method return value with "f": 0.123457
np.float32 formatted by an f-string: 0.12345678359270096
float __str__ method return value: 0.12345678359270096
float __repr__ method return value: 0.12345678359270096
float __format__ method return value with "f": 0.123457
float formatted by an f-string: 0.12345678359270096
It's apparent that printing a numpy.float32
through an f-string actually prints the float
conversion of that numpy.float32
. The f-string first converts the value of x
to a Python float
and then handles it as it would a float
normally, effectively giving you its string representation, instead of that of the numpy.float32
. (this answers the question, the below just provides some extra background)
The reason for all the extra digits that you didn't define are of course the result of floating point imprecision. Floats can only approximate specific real numbers, and when you don't specifically track the precision, you end up with representations of the closest value they can represent. 0.12345678
can't be the exact value of a float
.
Edit: Note that user @markransom pointed out another interesting quirk you may run into when using Python 2, namely that __str__
and __repr__
would give different results Why does str(float) return more digits in Python 3 than Python 2?
Also, in case you are wondering what is going on with floats in detail, have a look at this:
import struct
import math
x = 0.12345678
# IEEE 754 binary representation of the float
binary = struct.unpack('!Q', struct.pack('!d', x))[0]
# Extract sign, exponent, and mantissa
sign = (binary >> 63) & 0x1
exponent = ((binary >> 52) & 0x7FF) - 1023 # Unbias the exponent
mantissa = binary & ((1 << 52) - 1) # Lower 52 bits
# Reconstruct the value, and the next possible value
value = (-1)**sign * (1 + mantissa / 2**52) * 2**exponent
prev_value = (-1)**sign * (1 + (mantissa-1) / 2**52) * 2**exponent
print(math.isclose(x, value, rel_tol=1e-15)) # True if reconstructed correctly
print(sign, exponent, mantissa, f'{mantissa:b}') # Show sign, exponent, and mantissa (and in binary)
print(f'{value:.56f}') # Show exact value stored in float
print(f'{prev_value:.56f}')
Output
True
0 -4 4392398907099285 1111100110101101110100010000100100011100100010010101
0.12345678000000000207325712153760832734405994415283203125
0.12345677999999998819546931372315157204866409301757812500
This shows you the size difference for the ULP (Unit in Last Place), starting with the number you gave and the closest smaller number. Those two are the closest you can get to 0.12345678
with a float
.
And finally, note that a numpy.float32
uses a different (smaller) representation, which has different limitations, which explains why you end up with a different representation - which is farther from the value than the closest Python can get.
- 谷歌继续封死华为后路,Mate 30无法安装谷歌服务
- 纳德拉:微软所有软件将转向包年订户模式
- 移动互联网生态基石平台的吸引力分析
- Windows8是备胎?解析微软移动市场战略
- rust - Why do I have to use &char instead of char to index a key in a HashMap<char, i32>? - Stack Overflow
- open source - Langgraph State not being passed properly with Ollama - Stack Overflow
- python - Error with modules aiogram 3.0, how to fix? - Stack Overflow
- dataframe - Dataset uploaded and verified, but cannot use read.csv - Stack Overflow
- node.js - Mongoose schema worked with the main db but not with test db - Stack Overflow
- flutter - App Name Not Updating in Android Recent Apps View Despite Manifest and Strings Configuration - Stack Overflow
- maven - Quarkus Live Reload in nested directories - Stack Overflow
- ios - CocoaPods could not find compatible versions for pod "FirebaseCore": - Stack Overflow
- r - Elegant vectorization of nested for loop - Stack Overflow
- react native - Top SafeArea on iOS cannot be ignored - Stack Overflow
- amazon web services - Python boto3: download files from s3 to local only if there are differences between s3 files and local one
- window - Strawberry Perl doesn't include Win32::shortcut? - Stack Overflow
- java - Android physical keyboard support for key press and hold - Stack Overflow