Skip to content

Floating point accuracy for sin and cos with range constraint #914

Open

Description

@philloooo

It looks like currently we don't define the accuracy of floating point operations.

I am running into an issue with the cos and sin web platform tests:

  • WGSL spec defines floating point accuracy for some built-in functions.
  • For cos, and sin , the allowed error is at most 2**-11 for fp32 and 2**-7 for fp16. However it's only for values within [-π, π]
  • Our WPTs contains inputs outside of the range.

So currently some fp16 tests are failing in some bots for tflite gpu backend with output diff greater than 2**-7.

I think we can either:
a. align with the WGSL spec, so no guarantee for inputs outside of [-π, π]. And update the WPTs.
b. using the periodicity of the cos/sin function, perform range reduction by emulation before calling cos.

@fdwr @huningxin

Activity

  1. huningxin commented on Jan 6, 2026

    @huningxin
    Contributor

    @philloooo

    a. align with the WGSL spec, so no guarantee for inputs outside of [-π, π]. And update the WPTs.

    SGTM. WebNN WPT cos / sin tests already follow WGSL accuracy: https://chromium-review.googlesource.com/c/chromium/src/+/7204672

    /cc @BruceDai

  2. BruceDai commented on Jan 7, 2026

    @BruceDai
    Contributor

    Thanks @philloooo!

    Although the sin and cos functions are periodic with a fundamental period of 2π. But the number π is an irrational number, its decimal representation never ends, so I agree with your suggestion of limiting their input data value to be in the interval [-π, π].

    And there's same problem for tan operator. We also need do it for tan to align with below in WGSL spec.

    tan(x) | Inherited from sin(x) / cos(x)
    
  3. fdwr commented on Jan 7, 2026

    @fdwr
    Collaborator

    no guarantee for inputs outside of [-π, π].

    I'm fine with that.

    For comparison, here are the D3D and Vulkan tolerances:

    Direct3D Instructions (sincos)

    Theta values can be any IEEE 32-bit floating point values. ... The maximum absolute error is 0.0008 in the interval from -100Pi to +100Pi. (🤔 though I'm unclear the expected float16 tolerance here)

    https://microsoft.github.io/DirectX-Specs/d3d/archive/D3D11_3_FunctionalSpec.htm#22.10.20%20sincos

    Direct3D shader compiler cos/sin intrinsics

            <Row Name="Cos">
                <Parameter Name="Validation.Type">Epsilon</Parameter>
                <Parameter Name="Validation.Tolerance">0.0008</Parameter>

    https://github.com/microsoft/DirectXShaderCompiler/blob/main/tools/clang/unittests/HLSLExec/ShaderOpArithTable.xml#L903

    Vulkan instructions

    For half- (16 bit) and single- (32 bit) precision instructions, precisions are required to be at least as follows
    ...
    Float32: Absolute error ≤2−11 inside the range [−π,π].
    Float16: Absolute error ≤2−7 inside the range [−π,π].

    https://web.archive.org/web/20230108150951/https:/registry.khronos.org/vulkan/specs/1.3-extensions/html/chap49.html#spirvenv-op-prec

  4. philloooo commented on Jan 7, 2026

    @philloooo
    ContributorAuthor

    Should we document the precision and input range in the spec?
    Probably will take some work to research the all primitive ops for all platforms, and we will also need a mechanism to get up to date with platform updates.

  5. fdwr commented on Jan 8, 2026

    @fdwr
    Collaborator

    @philloooo:

    Should we document the precision and input range in the spec?

    Maybe. We haven't added it to the spec so far because it's tested by the WPT, the spec and the WPT could easily diverge if not kept in sync, and we didn't know which all the backends would end up supporting WebNN or the degree of divergence they would have in their results (you kinda have to implement it first before you can know the surprises 😉).

    Probably will take some work to research the all primitive ops for all platforms

    Much of the tolerance estimation was done years ago (using ONNX conformance tests and DirectML tests as inspiration, plus a lot of thinking about operator behavior :b), and I expect that primitive operators would have very similar results across current and future implementations (besides trigonometric and exponentials) as what we already have. I'm more concerned about the ones that perform reduction (convolution, gemm, reduceFoo...) and have divisions in them (normalizeFoo...), and especially the minigraph operators (lstm, gru). See:

    I wouldn't bother putting them in the spec yet until we verify the results of all the current backends with the WPT's. I know the implementation status of the backends is pretty mature, but I'm unsure where we stand for test coverage of each, and their passing rates (Bruce probably knows). Note my tolerance estimates were reasonable stakes in the ground, but I always knew we'd have to loosen some after more backend experience (and I'm sure FireFox's future implementation would add more data).

  6. mwyrzykowski commented on Jan 29, 2026

    @mwyrzykowski

    For reference, here is a link to how WebGPU describes the floating point guarantees in the specification:
    https://www.w3.org/TR/WGSL/#differences-from-ieee754

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

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions