public static class WaterMathThe arithmetic both hosts of the evaluator agree on, to the last bit.
Remarks
[35 § Risks](../../docs/plan/35-water.md#risks), decided in W1 rather than discovered in W7. The seam test between the C# evaluator and the Raven one states a tolerance of exact, and exact float agreement between a CPU and a SPIR-V implementation is a real claim that sin and cos do not support: the Vulkan specification allows OpSin 8192 ULP of error over the useful range, and a driver is free to use a hardware special-function unit whose polynomial nobody has written down.
So the wave sum does not call the intrinsic on either side. It calls SinCos, which is a stated polynomial in stated operations — and Raven/Library/Water/Surface.rvn spells out the same one.
⚠ What that actually bought, measured rather than claimed. Doc 35 asked for exact, and WaterSurfaceSeamDeviceTests measures 2 × 10⁻⁴ m — because a device is free to contract a multiply and an add into one FMA even where the source does not, and the Metal translation layer this repository's Vulkan device runs behind does. The residue is a one-ULP difference in the phase, and it therefore grows linearly with it: a millionth of a metre at a hundred radians, a twentieth of a millimetre at five thousand. Against the intrinsic's licensed 8192 ULP — which at those phases is not a rounding difference but a different wave — the polynomial is still what makes any bound sayable.
⚠ The range reduction is the part that has to be exact, not the polynomial. A polynomial evaluated on a reduced argument is a handful of fused-free multiply-adds and will agree anywhere; the reduction subtracts a multiple of π, and by a phase of a hundred thousand radians — twenty minutes of water time at a plausible frequency — a naive subtraction has lost every digit that mattered. Reduce therefore splits π into four pieces, the first three of which carry few enough significant bits that multiplying them by the number of half-cycles is exact, and subtracts them in order.
⚠ Nothing here may be rewritten into a fused multiply-add. An FMA computes one rounding where the written expression computes two, so a host that contracts and a host that does not disagree in the last bit — which is the whole of what this file exists to prevent. C# does not contract on its own and Raven's emitters are told not to; the parenthesisation below is load-bearing and not style.
Fields and properties (5)
public const float PiAThe first and largest piece of π: 201 ⁄ 64, which is nine significant bits.
public const float PiBThe second piece, also exact against its multiplier.
public const float PiCThe third.
public const float PiDAnd the remainder, which carries what is left of π's tail.
public const float TauTwo π.
Methods (8)
public static void SinCos(float radians, out float sin, out float cos)The sine and cosine of an angle, by the polynomial both hosts implement.
public static float Sin(float radians)The sine of an angle, by SinCos.
public static float Cos(float radians)The cosine of an angle, by SinCos.
public static float Reduce(float radians, out bool flipped)Brings an angle into [−π, π], saying whether the sign has to flip.
public static uint Hash(uint seed, int index)A hash of a seed and an index, for a spectrum that is the same everywhere.
public static float Unit(uint hash, int stream)One of a hash's several independent 0…1 draws.
public static float Saturate(float value)Clamps to 0…1.
public static float SmoothStep(float edge0, float edge1, float value)A smooth 0…1 ramp between two edges, with zero derivative at both.
Used by (11)
- BuoyancyVixen.Water
- GerstnerWaveVixen.Water
- WaterAttenuationVixen.Water
- WaterBodyVixen.Water
- WaterEvaluatorVixen.Water
- WaterFieldVixen.Water
- WaterMathTestsVixen.Water.Tests
- WaterProfilePointVixen.Water
- WaterRipplesVixen.Water
- WaterSurfaceMeshVixen.Water
- WaterWaveSpectrumVixen.Water