dotnet / dotnet/runtime

MathF.FusedMultiplyAdd incorrectly rounds subnormal results on musl's software fallback

Open
#133,349 1 comment 0 reactions 0 assignees View on GitHub
area-System.Numerics os-linux-musl
Dominant language
C#
Stars
18.3k
Forks
5.6k
PR merge metrics
PR metrics pending

Description

The inputs and underlying musl bug are described in [this article](https://shnatsel.github.io/implementing-fma-finding-bugs-in-std/)

### Description

`MathF.FusedMultiplyAdd` incorrectly rounds some subnormal results when its software fallback calls musl's `fmaf`. The same inputs produce different results with and without hardware FMA.

### Reproduction Steps

Create a .NET 10 console app on musl-based Linux, such as Alpine:

```sh
dotnet new console -f net10.0
```

Replace `Program.cs` with:

```csharp
float x = BitConverter.UInt32BitsToSingle(0x97000800);
float y = BitConverter.UInt32BitsToSingle(0x1cfff001);
float z = BitConverter.UInt32BitsToSingle(0x00010002);

Console.WriteLine($"0x{BitConverter.SingleToUInt32Bits(MathF.FusedMultiplyAdd(x, y, z)):x8}");
```

Force the software fallback:

```sh
DOTNET_EnableHWIntrinsic=0 DOTNET_ReadyToRun=0 dotnet run -c Release
```

### Expected behavior

```text
0x00010001
```

This is the correctly rounded result and is also returned with hardware FMA enabled.

### Actual behavior

```text
0x00010002
```

### Configuration

Reproduced with .NET 10.0.11 (`linux-musl-x64`) and musl 1.2.5-r12 from Alpine 3.22, using the default round-to-nearest, ties-to-even mode.

### Other information

[CoreCLR's fallback delegates to `fmaf`](https://github.com/dotnet/runtime/blob/main/src/coreclr/vm/floatsingle.cpp#L162-L166). musl's halfway-case check does not account for subnormal results, leading to double rounding. `Vector128.FusedMultiplyAdd` also reproduces the incorrect result through its scalar fallback.

Contributor guide

Open the contributing guide

Research direction

Start with the fallback delegation in src/coreclr/vm/floatsingle.cpp around the linked fmaf call, then reproduce the output using the provided Program.cs on Alpine or another musl-based Linux environment with the listed environment variables. Done means the software fallback returns 0x00010001 for the supplied inputs, matching hardware FMA, including the Vector128.FusedMultiplyAdd scalar fallback.

Written by the indexing model from the issue text.

Assessment

Tech stack
csharp, linux
Domain
operating-systems
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Active
Clarity
Mostly clear
Newbie friendliness
55/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.