Skip to content

BigInteger conversions to float, Half, and BFloat16 risk double rounding #125837

@stephentoub

Description

@stephentoub

Note

This issue was generated by GitHub Copilot CLI based on a review comment by @tannergooding on PR #125799.

Description

The explicit conversion operators from BigInteger to float, Half, and BFloat16 all convert via double as an intermediate step, which risks double rounding bugs:

https://github.com/dotnet/runtime/blob/23ee9c7a1d0d2b4b97e5e99ce09dcd7e7e55edc7/src/libraries/System.Runtime.Numerics/src/System/Numerics/BigInteger.cs#L2120

public static explicit operator float(BigInteger value) => (float)((double)value);
public static explicit operator Half(BigInteger value) => (Half)(double)value;
public static explicit operator BFloat16(BigInteger value) => (BFloat16)(double)value;

Problem

Converting BigInteger → double → float (or Half/BFloat16) performs two sequential rounding steps:

  1. Round the arbitrary-precision integer to double (53-bit mantissa)
  2. Round the double to the target type (24-bit for float, 11-bit for Half, 8-bit for BFloat16)

The composition of two correctly-rounded operations is not guaranteed to produce a correctly-rounded result. When the BigInteger value falls exactly at a double-rounding boundary, the intermediate double representation can cause the final result to be off by 1 ULP in the target type.

Expected Fix

Each of these conversions should handle the rounding directly from BigInteger to the target floating-point type, without an intermediate double step. This would ensure correctly-rounded results for all inputs.

Affected APIs

  • (float)(BigInteger)BigInteger.cs line 2120
  • (Half)(BigInteger)BigInteger.cs line 1990
  • (BFloat16)(BigInteger)BigInteger.cs line 1995

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions