Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Unexpected Floating-Point Results (ESP32-S3) #1563

Open
LEI-Hongfaan opened this issue Dec 8, 2024 · 1 comment
Open

Unexpected Floating-Point Results (ESP32-S3) #1563

LEI-Hongfaan opened this issue Dec 8, 2024 · 1 comment

Comments

@LEI-Hongfaan
Copy link

Library/API/IoT binding

NF-Interpreter, CoreLibrary, Runtime.Native

Visual Studio version

No response

.NET nanoFramework extension version

No response

Target name(s)

ESP32-S3

Firmware version

No response

Device capabilities

No response

Description

The ESP32-S3 has a hardware single-precision FPU, but the following code produces unexpected results. I believe these methods could be effectively implementable using integers, even without the FPU. Additionally, I am confused about the floating-point model in nanoFramework. Should it adhere to the IEEE 754 standard?

How to reproduce

Console.WriteLine($@"L001 {SystemInfo.FloatingPointSupport}");
Console.WriteLine($@"L002 {(0.0F) == (-0.0F)}");
Console.WriteLine($@"L003 {(0.0F).Equals(-0.0F)}");
Console.WriteLine($@"L004 {(float.NaN).Equals(float.NaN)}");

Outputs

L001 1
L002 True
L003 False
L004 True

1 == FloatingPoint.SinglePrecisionSoftware

Expected behaviour

L001 3
L002 True
L003 True
L004 True

3 == FloatingPoint.SinglePrecisionHardware

Screenshots

No response

Sample project or code

No response

Aditional information

I have found code that appears to correctly compare floating point numbers. However, this code is guarded by certain macros.

            //--//
#if !defined(NANOCLR_EMULATED_FLOATINGPOINT)

            case DATATYPE_R4:

                // deal with special cases:
                // return 0 if the numbers are unordered (either or both are NaN)
                // this is post processed in interpreter so '1' will turn into '0'
                if (__isnand(left.NumericByRefConst().r4) && __isnand(right.NumericByRefConst().r4))
                {
                    return 1;
                }

                // The infinite values are equal to themselves.
                // this is post processed in interpreter so '0' will turn into '1'
                else if (__isinfd(left.NumericByRefConst().r4) && __isinfd(right.NumericByRefConst().r4))
                {
                    return 0;
                }
                // all the rest now
                else
                {
                    if (isgreater(left.NumericByRefConst().r4, right.NumericByRefConst().r4))
                    {
                        return 1;
                    }
                    else if (isless(left.NumericByRefConst().r4, right.NumericByRefConst().r4))
                    {
                        return -1;
                    }
                    else
                    {
                        return 0;
                    }
                }

            case DATATYPE_R8:

                // deal with special cases:
                // return 0 if the numbers are unordered (either or both are NaN)
                // this is post processed in interpreter so '1' will turn into '0'
                if (__isnand((double)left.NumericByRefConst().r8) || __isnand((double)right.NumericByRefConst().r8))
                {
                    return 1;
                }

                // The infinite values are equal to themselves.
                // this is post processed in interpreter so '0' will turn into '1'
                else if (
                    __isinfd((double)left.NumericByRefConst().r8) && __isinfd((double)right.NumericByRefConst().r8))
                {
                    return 0;
                }
                // all the rest now
                else
                {
                    if (isgreater((double)left.NumericByRefConst().r8, (double)right.NumericByRefConst().r8))
                    {
                        return 1;
                    }
                    else if (isless((double)left.NumericByRefConst().r8, (double)right.NumericByRefConst().r8))
                    {
                        return -1;
                    }
                    else
                    {
                        return 0;
                    }
                }

#else
            case DATATYPE_R4:
            case DATATYPE_R8:
                fSigned = true;
#endif
@Ellerbach
Copy link
Member

Short answer: it all depends on the native side support of floating point. We're just using those. In MCU some, if can be perfect, in some others, not. We're not rewriting this part and just use what's in each vendors SDK and chips.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants