From 55a3b3eb81a1c37b0c5345e68c03520c85564e3d Mon Sep 17 00:00:00 2001 From: sterni Date: Sat, 5 Aug 2023 16:07:35 +0200 Subject: feat(sterni/nix): add trivial float library Only implements the different conversion types from and to ints for now. Unfortunately very reliant on builtins.{floor,ceil} which can't be implemented purely except very inefficiently (to my knowledge), so it only really works for C++ Nix >= 2.4. Tests are thus skipped for C++ Nix 2.3. Change-Id: Idcb1a11df11e214cdba3f2a0715472b370daa7dc Reviewed-on: https://cl.tvl.fyi/c/depot/+/9008 Reviewed-by: sterni Tested-by: BuildkiteCI --- users/sterni/nix/float/default.nix | 23 +++++++++++++++ users/sterni/nix/float/tests/default.nix | 49 ++++++++++++++++++++++++++++++++ users/sterni/nix/num/default.nix | 1 + 3 files changed, 73 insertions(+) create mode 100644 users/sterni/nix/float/default.nix create mode 100644 users/sterni/nix/float/tests/default.nix (limited to 'users/sterni') diff --git a/users/sterni/nix/float/default.nix b/users/sterni/nix/float/default.nix new file mode 100644 index 0000000000..ecb6465c88 --- /dev/null +++ b/users/sterni/nix/float/default.nix @@ -0,0 +1,23 @@ +{ depot, ... }: + +let + inherit (depot.users.sterni.nix) + num + ; +in + +rec { + # In C++ Nix, the required builtins have been added in version 2.4 + ceil = builtins.ceil or (throw "Nix implementation is missing builtins.ceil"); + floor = builtins.floor or (throw "Nix implementation is missing builtins.floor"); + + truncate = f: if f >= 0 then floor f else ceil f; + round = f: + let + s = num.sign f; + a = s * f; + in + s * (if a >= floor a + 0.5 then ceil a else floor a); + + intToFloat = i: i * 1.0; +} diff --git a/users/sterni/nix/float/tests/default.nix b/users/sterni/nix/float/tests/default.nix new file mode 100644 index 0000000000..75e2a1bfa0 --- /dev/null +++ b/users/sterni/nix/float/tests/default.nix @@ -0,0 +1,49 @@ +{ depot, lib, ... }: + +let + + inherit (depot.nix.runTestsuite) + runTestsuite + it + assertEq + ; + + inherit (depot.users.sterni.nix) + float + ; + + testsBuiltins = it "tests builtin operations" [ + (assertEq "ceil pos" (float.ceil 1.5) 2) + (assertEq "ceil neg" (float.ceil (-1.5)) (-1)) + (assertEq "floor pos" (float.floor 1.5) 1) + (assertEq "floor neg" (float.floor (-1.5)) (-2)) + ]; + + testsConversionFrom = it "tests integer to float conversion" [ + (assertEq "float.intToFloat is identity for floats" (float.intToFloat 1.3) 1.3) + (assertEq "float.intToFloat converts ints" + (builtins.all + (val: builtins.isFloat val) + (builtins.map float.intToFloat (builtins.genList (i: i - 500) 1000))) + true) + ]; + + exampleFloats = [ 0.5 0.45 0.3 0.1 200 203.457847 204.65547 (-1.5) (-2) (-1.3) (-0.45) ]; + testsConversionTo = it "tests float to integer conversion" [ + (assertEq "round" + (builtins.map float.round exampleFloats) + [ 1 0 0 0 200 203 205 (-2) (-2) (-1) 0 ]) + (assertEq "truncate towards zero" + (builtins.map float.truncate exampleFloats) + [ 0 0 0 0 200 203 204 (-1) (-2) (-1) 0 ]) + ]; +in + +runTestsuite "nix.num" ([ + testsConversionFrom +] + # Skip for e.g. C++ Nix < 2.4 +++ lib.optionals (builtins ? ceil && builtins ? floor) [ + testsConversionTo + testsBuiltins +]) diff --git a/users/sterni/nix/num/default.nix b/users/sterni/nix/num/default.nix index 6404930837..81e2f8377f 100644 --- a/users/sterni/nix/num/default.nix +++ b/users/sterni/nix/num/default.nix @@ -8,6 +8,7 @@ rec { sub ; + sign = i: if i < 0 then -1 else 1; abs = i: if i < 0 then -i else i; inRange = a: b: x: x >= a && x <= b; -- cgit 1.4.1