Skip to content

Switch expression in C# 8 behaves differently on x86 vs x64 android #68906

@mkhamoyan

Description

@mkhamoyan

Description

Switch expression in C# 8 behaves differently on x86 vs x64 Android. After third call it behaves differently for float type.

Reproduction Steps

Copy paste the below code in mono/samples/Android and try to run on x86 android emulator.
GetNumberAsString after third call starts returning NAN, even if it is called for the same value (float.MaxValue).

public static int Main(string[] args)
    {
        var random = new Random(42);

        List<float> Floats = new List<float>
        {
                // 0.000f,
                //1.1234e1f,
                //-1.1234e1f,
                float.MaxValue,
                float.MinValue
        };

        for (int i = 0; i < 10; i++)
        {
            float value = NextFloat(random);
            Floats.Add(value);
        }
        Console.WriteLine ("GetNumberAsString conversion is {0}", GetNumberAsString(float.MaxValue));
        Console.WriteLine ("GetNumberAsString conversion is {0}", GetNumberAsString(Floats[3]));
        Console.WriteLine ("GetNumberAsString conversion is {0}", GetNumberAsString(Floats[4]));
        Console.WriteLine ("GetNumberAsString conversion is {0}", GetNumberAsString(Floats[5]));
        Console.WriteLine ("GetNumberAsString conversion is {0}", GetNumberAsString(float.MaxValue));


        //RunAsRootTypeTest(Floats);
        return 42;
    }

    public static float NextFloat(Random random)
    {
        double mantissa = (random.NextDouble() * 2.0) - 1.0;
        double exponent = Math.Pow(2.0, random.Next(-126, 128));
        float value = (float)(mantissa * exponent);
        return value;
    }

    private static void RunAsRootTypeTest<T>(List<T> Floats)
    {
        foreach(T f in Floats)
        {
            Console.WriteLine ("GetNumberAsString from foreach conversion is {0}", GetNumberAsString(f));
        }
    }
    
    private static string GetNumberAsString<T>(T number)
    {            
        /*switch (Type.GetTypeCode(typeof(T)))
        {
            case TypeCode.Double:
            return Convert.ToDouble(number).ToString("G9", System.Globalization.CultureInfo.InvariantCulture);
            case TypeCode.Single:
            return Convert.ToSingle(number).ToString("G9", System.Globalization.CultureInfo.InvariantCulture);
            case TypeCode.Decimal:
            return Convert.ToDecimal(number).ToString(System.Globalization.CultureInfo.InvariantCulture);
            default:
            return number.ToString();
            }*/
            
            return number switch
            {
                double @double => @double.ToString("G9", System.Globalization.CultureInfo.InvariantCulture),
                float @float => @float.ToString("G9", System.Globalization.CultureInfo.InvariantCulture),
                decimal @decimal => @decimal.ToString(System.Globalization.CultureInfo.InvariantCulture),
                _ => number.ToString()
            };

    }

Expected behavior

GetNumberAsString should convert correctly after third call also.
To get expected behaviour please uncomment first switch in GetNumberAsString and comment last one.
TypeCode enum switch works correct on both x64 and x86, so my guess is switch expression in C# 8 behaves differently on x86 vs x64 Android.

Actual behavior

First 3 times GetNumberAsString returns correct value. After that it starts to return NAN.

Regression?

No response

Known Workarounds

Using TypeCode enum switch works fine on both x64 and x86.

Configuration

Try on Android x86.

Other information

return number switch
            {
                //double @double => @double.ToString("G9", System.Globalization.CultureInfo.InvariantCulture),
                float @float => @float.ToString("G9", System.Globalization.CultureInfo.InvariantCulture),
                //decimal @decimal => @decimal.ToString(System.Globalization.CultureInfo.InvariantCulture),
                _ => number.ToString()
            };

When I comment other cases in switch seems it works.

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions