I am looking to implement the RandomX Proof of Work hash function in JavaScript + WebAssembly. The README explains how this isn’t possible:
Web mining is infeasible due to the large memory requirement and the lack of directed rounding support for floating point operations in both Javascript and WebAssembly.
Due to the pervasive use of repeatedly switching the rounding modes using a CFROUND
instruction inside the bytecode and the fact that JavaScript has no ability to change the rounding mode or even use any other rounding mode other than ties to even, its impossible.
The CFROUND
instruction manipulates the fprc
abstract register inside the RandomX spec. fprc
starts at zero, so round ties to even and is updated seemingly randomly on every instruction execution.
fprc |
rounding mode |
---|---|
0 | roundTiesToEven |
1 | roundTowardNegative |
2 | roundTowardPositive |
3 | roundTowardZero |
RandomX uses 5 properly rounded operations, add, sub, mul, div, and sqrt guaranteed to be properly rounded by the IEEE754 spec in double precision. My question is this. Soft float is not an option, I have access to floating point arithmetic only in round ties to even for those 5 operations. I need to find a way to emulate double precision arithmetic with all of the other rounding modes implemented in terms of one rounding mode for those 5 operations. This would be much faster than soft float.
Bruce at the Random ASCII blog had something to say:
If I understand correctly then the other three rounding modes will produce results that are either identical to round-to-nearest-even or one ULP away. If the round-to-nearest-even operation is exact then all rounding modes will give the same result. If it is not exact then you’d have to figure out which results would be different. I think that either round-towards-negative or round-towards-positive would be one ULP away, but not both.
FMA (fused multiply add) operations aren’t available in JavaScript, however they are available in WebAssembly but gated behind non deterministic operations (which aren’t widely supported). Those operations are f32x4.relaxed_*madd
and f64x2.relaxed_*madd
. If the use of FMA is required, this is fine, I can implement fallbacks.
The only paper that was even slightly close to floating point rounding mode emulation was Emulating round-to-nearest ties-to-zero ”augmented” floating-point operations using round-to-nearest ties-to-even arithmetic. It makes some interesting points but not useful.
This is a question that I am not qualified to answer, but I believe its possible. How could I?
This is as far as I tried to emulate round toward zero in terms of round to nearest, ties to even.
double add_fe_towardzero(double a, double b) {
if (a + b >= 0) {
return (a + b + 0.5 * ulp(a + b)) - 0.5 * ulp(a + b);
} else {
return (a + b - 0.5 * ulp(a + b)) + 0.5 * ulp(a + b);
}
}
I have a test harness iterating over a random selection of floating point values and computing the outputs from the reference and the implementation and comparing them similar to the post There are Only Four Billion Floats–So Test Them All! The above function has a 1/4 success rate, not 100%.
l-m is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.