---
title: "Compute deterministic sine and cosine in C#"
url: https://recursiveai.org/onemath/cookbook/deterministic-trigonometry/
description: "Compute deterministic sine and cosine in C# with a complete runnable example, real output and the behavior to check before using the result. Free, open-source .NET code."
version: "1.0.0"
---

# Compute deterministic sine and cosine in C#

**OneMath** is a free, open-source deterministic math library for .NET from Recursive AI. MIT or Apache-2.0, no native dependencies.

[NuGet](https://www.nuget.org/packages/RecursiveAI.OneMath) · [GitHub](https://github.com/recursive-ai-oss/onemath-csharp) · [Docs](https://recursiveai.org/onemath/docs/) · [Download example (.zip)](https://recursiveai.org/onemath/cookbook/deterministic-trigonometry/deterministic-trigonometry.zip)

Compute sine and cosine with reproducible floating-point bits. Angles are in radians.

```shell
dotnet add package RecursiveAI.OneMath
```

Requires [.NET 10](https://dotnet.microsoft.com/download/dotnet/10.0) (net10.0); .NET 9 and earlier aren’t supported.

```csharp
using RecursiveAI.OneMath;

var (sin, cos) = Math64.SinCos(1.0);
Console.WriteLine($"{sin:R}, {cos:R}");
```

```text
0.8414709848078965, 0.5403023058681398
```

Unzip [the example](https://recursiveai.org/onemath/cookbook/deterministic-trigonometry/deterministic-trigonometry.zip), then `dotnet run`.

## The full program

The full program computes both precisions for one radian and prints their numeric values and hexadecimal bit patterns. Its final two lines check infinite input and an inverse-trigonometry domain error; these return NaN rather than throwing.

```csharp
using RecursiveAI.OneMath;

var (sin64, cos64) = Math64.SinCos(1.0);
var (sin32, cos32) = Math32.SinCos(1.0f);
Console.WriteLine($"sin64: {sin64:R} 0x{BitConverter.DoubleToUInt64Bits(sin64):X16}");
Console.WriteLine($"cos64: {cos64:R} 0x{BitConverter.DoubleToUInt64Bits(cos64):X16}");
Console.WriteLine($"sin32: {sin32:R} 0x{BitConverter.SingleToUInt32Bits(sin32):X8}");
Console.WriteLine($"cos32: {cos32:R} 0x{BitConverter.SingleToUInt32Bits(cos32):X8}");
Console.WriteLine($"Infinite input: {double.IsNaN(Math64.Sin(double.PositiveInfinity))}");
Console.WriteLine($"Outside asin domain: {double.IsNaN(Math64.Asin(2))}");
```

`dotnet run` prints:

```text
sin64: 0.8414709848078965 0x3FEAED548F090CEE
cos64: 0.5403023058681398 0x3FE14A280FB5068C
sin32: 0.84147096 0x3F576AA4
cos32: 0.5403023 0x3F0A5140
Infinite input: True
Outside asin domain: True
```

## Variations

Call sine and cosine separately when you do not need the pair:

```csharp
using RecursiveAI.OneMath;

Console.WriteLine(Math32.Sin(0.5f));
Console.WriteLine(Math32.Cos(0.5f));
Console.WriteLine(Math64.Sin(1e300));
```

```text
0.47942555
0.87758255
-0.8178819121159085
```

## Related recipes

- [Check that machines agree](https://recursiveai.org/onemath/cookbook/check-machines-agree/)
- [Vector and quaternion math](https://recursiveai.org/onemath/cookbook/vector-and-quaternion-math/)

## The short answer

Use `Math64.SinCos(radians)` for doubles or `Math32.SinCos(radians)` for floats. The tuple contains sine first and cosine second. Both functions also have separate `Sin` and `Cos` methods. Choose the input precision deliberately: `1.0f` and `1.0` select different floating-point representations even when they denote the same exact number.

The [elementary-functions contract](https://recursiveai.org/onemath/docs/functions/) says every function is correctly rounded for every input: round to nearest, ties to even, with gradual underflow and overflow to infinity. It states that results are bit-identical on every platform. That is a claim about the function’s result for a given input, not a promise that unrelated application code will choose the same input.

## Is floating point math deterministic?

`Math.Sin` and `Math.Cos` use platform math, so their results are not covered by OneMath’s same-bits guarantee across machines and runtimes. OneMath instead defines its own rounding and special-value behavior for both `Math32` and `Math64`, with the same result bits for the same input.

Reproducibility still starts with equal input bits. If one machine calculates its angle through a different expression, or your application changes units or precision, the function may receive a different value. Keep your input data, conversion rules and evaluation order consistent. The example fixes the input to one radian and prints the result’s bits to make that boundary visible.

The full program uses `BitConverter` to display hexadecimal representations. The double results have a different width from the float results. Decimal output is useful for people, but the bit representation distinguishes results without relying on how many decimal places you decide to display. Keep formatting separate from the calculation when comparing runs.

## How do I compute deterministic sine and cosine in C#?

Use the tuple-returning call in the snippet at the top, or the separate calls in the variation. `Math32` rounds its result to float precision; it is not simply a promise that taking a rounded double result and casting it yourself will always give the intended float result. The documentation says float inputs are widened exactly and the final rounding differs.

Large finite angles are supported; the variation includes `Math64.Sin(1e300)`. Do not reduce such an angle using a rounded multiple of π in your own code first and expect to retain the original input’s result. Passing the original value lets the function perform its own argument handling.

Non-finite inputs and domain errors do not become exceptions. The example checks that sine of positive infinity and arcsine of 2 return NaN. The functions documentation also specifies canonical `double.NaN` or `float.NaN` for every NaN result, regardless of input payload. This is the elementary-functions contract; do not generalize it to every operation on vectors and matrices, whose NaN payload rules are documented separately. Validate inputs before calculation if NaN is not an acceptable value in your application’s state.
