The original article [^1] didn't specify the CPU, but I gathered the code examples (and added one for Lua, untested) if anyone is curious to try with arm64. The test case to compare the margin of error was eml_mul(2, 3).
JavaScript
const eml = (x, y) => Math.exp(x) - Math.log(y);
const emlLn = (x) => eml(1, eml(eml(1, x), 1));
const emlMul = (x, y) => eml(emlLn(x) + emlLn(y), 1);
const emlAdd = (x, y) => emlLn(eml(x, 1) * eml(y, 1));
Python
import math
def eml(x, y):
return math.exp(x) - math.log(y)
def eml_ln(x):
return eml(1, eml(eml(1, x), 1))
def eml_mul(x, y):
return eml(eml_ln(x) + eml_ln(y), 1)
def eml_add(x, y):
return eml_ln(eml(x, 1) * eml(y, 1))
PHP
function eml(float $x, float $y): float {
return exp($x) - log($y);
}
function eml_ln(float $x): float {
return eml(1, eml(eml(1, $x), 1));
}
function eml_mul(float $x, float $y): float {
return eml(eml_ln($x) + eml_ln($y), 1);
}
function eml_add(float $x, float $y): float {
return eml_ln(eml($x, 1) * eml($y, 1));
}
Go
func eml(x, y float64) float64 {
return math.Exp(x) - math.Log(y)
}
func emlLn(x float64) float64 {
return eml(1, eml(eml(1, x), 1))
}
func emlMul(x, y float64) float64 {
return eml(emlLn(x)+emlLn(y), 1)
}
func emlAdd(x, y float64) float64 {
return emlLn(eml(x, 1) * eml(y, 1))
}
Rust
fn eml(x: f64, y: f64) -> f64 {
x.exp() - y.ln()
}
fn eml_ln(x: f64) -> f64 {
eml(1.0, eml(eml(1.0, x), 1.0))
}
fn eml_mul(x: f64, y: f64) -> f64 {
eml(eml_ln(x) + eml_ln(y), 1.0)
}
fn eml_add(x: f64, y: f64) -> f64 {
eml_ln(eml(x, 1.0) * eml(y, 1.0))
}
Lua
local math = require("math")
function eml(x, y)
return math.exp(x) - math.log(y)
end
function eml_ln(x)
return eml(1, eml(eml(1, x), 1))
end
function eml_mul(x, y)
return eml(eml_ln(x) + eml_ln(y), 1)
end
function eml_add(x, y)
return eml_ln(eml(x, 1) * eml(y, 1))
end
---
[^1]: https://lilting.ch/en/articles/eml-single-operator-elementar...