Math.fround()
Math.fround(x) The Math.fround() function returns the nearest 32-bit single-precision float representation of a number. JavaScript numbers are 64-bit doubles by default, so calling fround deliberately reduces precision to match what a 32-bit float hardware register or a typed array like Float32Array would store.
The main use case is interoperability with APIs that work in 32-bit floats — WebGL uniforms, Web Audio gain values, and Float32Array buffers all operate at 32-bit precision. If you compute values in 64-bit and then pass them to such APIs, subtle rounding differences can accumulate. Applying fround first makes the rounding explicit and predictable.
Syntax
Math.fround(x)
Parameters
| Parameter | Type | Description |
|---|---|---|
x | number | The value to convert to the nearest 32-bit float |
Return value
The nearest 32-bit single-precision float representation of x. Returns NaN for non-numeric input, 0 for ±0, and Infinity for values outside the 32-bit float range.
Examples
Basic usage
console.log(Math.fround(1));
// 1
console.log(Math.fround(1.5));
// 1.5
console.log(Math.fround(1.23456789));
// 1.2345679
Values that fit exactly in a 32-bit float return unchanged. Values with more decimal precision get rounded to the nearest representable 32-bit value. The examples above stay safely within 32-bit range, but not all JavaScript numbers survive the conversion unscathed — classic floating-point sums like 0.1 + 0.2 produce different representations at 32-bit and 64-bit precision.
Precision loss demonstration
const original = 0.1 + 0.2;
console.log(original);
// 0.30000000000000004
console.log(Math.fround(original));
// 0.30000001192092896
// The fround result is the actual 32-bit float representation
const frounded = Math.fround(0.1 + 0.2);
console.log(frounded === 0.30000001192092896);
// true
Both results are “wrong” compared to the true mathematical sum, but they are wrong in different ways. Knowing which way your target API will round helps you match values correctly. The fround result matches what a Float32Array would store, while the unfrounded value reflects the default 64-bit computation. This gap between the two representations is measurable — and the next example shows exactly how large the discrepancy can be for common constants.
Comparing with full precision
const value = Math.PI;
console.log(value);
// 3.141592653589793
console.log(Math.fround(value));
// 3.1415927
// The difference
console.log(value - Math.fround(value));
// 6.98491930961609e-10
The difference between the original and the fround value is tiny — roughly 7 × 10⁻¹⁰ for Pi — but it is measurable. Beyond individual comparisons, the 32-bit float format imposes absolute limits on which integer values can be represented at all. Once you exceed the significand width, consecutive integers start sharing the same float representation, and precision drops sharply.
Large numbers
console.log(Math.fround(1e10));
// 10000000000
console.log(Math.fround(1.7976931348623157e+308));
// Infinity (exceeds 32-bit float range)
// Near the precision limit
console.log(Math.fround(16777216));
// 16777216
console.log(Math.fround(16777217));
// 16777216 (loses precision at this scale)
The 32-bit float format has a 23-bit significand, which means integers above 16,777,216 (2²⁴) cannot all be represented exactly. Beyond the numbers themselves, the real motivation for fround is API compatibility. Many browser APIs that deal with graphics or audio expect 32-bit precision, and explicitly narrowing before you pass values avoids hidden rounding mismatches between your JavaScript math and the underlying buffers.
Common patterns
WebGL compatibility
function setGLMatrixElement(gl, location, value) {
// Ensure 32-bit float precision for WebGL
const floatValue = Math.fround(value);
gl.uniform1f(location, floatValue);
}
// Without fround, you might get unexpected results
const shaderValue = Math.sin(Math.PI);
console.log(Math.fround(shaderValue));
// 0
Writing shader values through WebGL is one of the most common scenarios for fround. Beyond sending data to the GPU, the same technique helps when you need to compare computed values against numbers that have already been stored in or retrieved from 32-bit typed arrays — the precision must match for the comparison to be meaningful.
Consistent floating-point comparisons
function floatsEqual(a, b, tolerance) {
return Math.abs(Math.fround(a) - Math.fround(b)) < tolerance;
}
console.log(floatsEqual(0.1 + 0.2, 0.3, 0.0001));
// true
Applying fround to both sides of a comparison produces consistent results even when the original computations happened at different precisions. The same narrowing technique applies to audio work, where gain values and other parameters may be constrained to 32-bit floats by the Web Audio API. Explicitly calling fround before setting these values ensures you can predict exactly what the audio system will receive.
Audio processing
class AudioProcessor {
constructor() {
this.gain = 0;
}
setGain(value) {
// Audio APIs often use 32-bit floats
this.gain = Math.fround(Math.max(0, Math.min(1, value)));
}
}
const processor = new AudioProcessor();
processor.setGain(0.755);
console.log(processor.gain);
// 0.7550000252723694
When fround() matters
For pure JavaScript arithmetic, the difference between 32-bit and 64-bit floats is usually invisible — the engine always works in 64-bit internally. Math.fround() only makes a difference when your code communicates with systems that operate in 32-bit float space:
- Writing to a
Float32Arraybuffer - Passing values to WebGL uniform variables
- Comparing JavaScript values against values read back from a 32-bit typed array
- Matching the behaviour of server-side code that uses C/C++
floatrather thandouble
If none of these apply, you do not need fround. The function is a precision-narrowing tool, not a general-purpose number formatter.
Checking Float32Array consistency
When you read a value back from a Float32Array, it has already been rounded to 32-bit precision. Comparing that readback value with the original 64-bit computation will fail even for simple numbers:
const arr = new Float32Array(1);
arr[0] = 0.1;
console.log(arr[0] === 0.1); // false
console.log(arr[0] === Math.fround(0.1)); // true
Math.fround lets you reproduce the rounding that Float32Array applies, so equality checks produce the correct result.
See Also
- Math.clz32() — count leading zeros in 32-bit representation
- Number.prototype.toFixed() — format numbers with fixed decimal places
- Math.trunc() — truncate to integer by removing fractional digits