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
Numerical accuracy when converting from Single to float #1896
I'm sorry it's me again with some weird low-level issue. I use a DLL where a function returns a System.Single. Its return value is 0.01. Before pythonnet version 3.0 this got converted to a Python float also of value 0.01. With Pythonnet 3.0 I get a Python float0.009999999776482582 instead. I can reproduce this issue by creating System.Single objects.
importclrimportSystem# Parse a string to avoid conversion from Python float to dotnetprint(System.Single.Parse('1e-2'))
# Create a pure dotnet object without conversion back to Python (I think .ToString() gets called here?)print(System.Single(0.01))
# Create a pure dotnet object without conversion back to Python and convert back to Pythonprint(System.Single(0.01).MemberwiseClone())
The three expressions perhaps surprisingly give values of two different types: the 1st and 3rd are Python float (which in CPython is a float64, so same as System.Double), and the 2nd is System.Single (float32). And the values are actually equal. The reason you see different strings has to do with how precision of the number type affects rounding.
The cause for type to be different is that in most cases any System.Single value returned to Python from a call to .NET is automatically widened without loss of precision to Python float (again, which is == float64 == System.Double) similarly to how System.Int32 is widened to Python int - for convenience. The direct invocation of System.Single "constructor" is AFAIK the only exception because it is used to explicitly convert type to System.Single in order to choose a .NET overload when necessary.
So I guess that WAT-like behavior is by design, and we won't change it in 3.0.0
Though while playing with your code I noticed that in 3.0 (at least) float(System.Single(42)) fails, and so does any attempt to use int() or float() on instances of primitive .NET types, which looks like a bug, but it also might be intentional.
@filmor thoughts on the float(System.Single(42)) issue?
Thank you, I did not know the video. I laughed out loud and can't wait to send it to colleagues tomorrow. 😂
Though while playing with your code I noticed that in 3.0 (at least) float(System.Single(42)) fails, and so does any attempt to use int() or float() on instances of primitive .NET types, which looks like a bug, but it also might be intentional.
That's reassuring, I thought I was just too stupid to make it a Python datatype again and therefore came up with
I guess float(Single(42)) used to work because we implicitly converted Single to Python's float. We currently don't implement __float__ or __int__ on any .NET types, that is what's missing here.
Activity
lostmsu commentedon Aug 3, 2022
Always check your types )
The three expressions perhaps surprisingly give values of two different types: the 1st and 3rd are Python
float(which in CPython is afloat64, so same asSystem.Double), and the 2nd isSystem.Single(float32). And the values are actually equal. The reason you see different strings has to do with how precision of the number type affects rounding.Sadly, it looks like the current behavior deserves its place in the famous JavaScript WAT video.
The cause for type to be different is that in most cases any
System.Singlevalue returned to Python from a call to .NET is automatically widened without loss of precision to Pythonfloat(again, which is ==float64==System.Double) similarly to howSystem.Int32is widened to Pythonint- for convenience. The direct invocation ofSystem.Single"constructor" is AFAIK the only exception because it is used to explicitly convert type toSystem.Singlein order to choose a .NET overload when necessary.So I guess that WAT-like behavior is by design, and we won't change it in 3.0.0
Though while playing with your code I noticed that in 3.0 (at least)
float(System.Single(42))fails, and so does any attempt to useint()orfloat()on instances of primitive .NET types, which looks like a bug, but it also might be intentional.@filmor thoughts on the float(System.Single(42)) issue?
My experiments:
m-rossi commentedon Aug 3, 2022
Thank you for that detailed explanation!
I guessed it's something related to this. That's why I chose that title with accuracy. Floats can be evil sometimes.
Thank you, I did not know the video. I laughed out loud and can't wait to send it to colleagues tomorrow. 😂
That's reassuring, I thought I was just too stupid to make it a Python datatype again and therefore came up with
filmor commentedon Aug 10, 2022
I guess
float(Single(42))used to work because we implicitly convertedSingleto Python'sfloat. We currently don't implement__float__or__int__on any .NET types, that is what's missing here.m-rossi commentedon Aug 10, 2022
As a workaround I can use
numpyfor the rescue and itsfloat32-datatype