about summary refs log tree commit diff
path: root/users/sterni
diff options
context:
space:
mode:
authorsterni <sternenseemann@systemli.org>2023-08-05T14·07+0200
committersterni <sternenseemann@systemli.org>2023-08-09T12·12+0000
commit55a3b3eb81a1c37b0c5345e68c03520c85564e3d (patch)
treefed17501809109ab90e8324732fdc68a32f1fee5 /users/sterni
parent984ea69386a47e753c4129e2a6230aa60b4584cd (diff)
feat(sterni/nix): add trivial float library r/6478
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 <sternenseemann@systemli.org>
Tested-by: BuildkiteCI
Diffstat (limited to 'users/sterni')
-rw-r--r--users/sterni/nix/float/default.nix23
-rw-r--r--users/sterni/nix/float/tests/default.nix49
-rw-r--r--users/sterni/nix/num/default.nix1
3 files changed, 73 insertions, 0 deletions
diff --git a/users/sterni/nix/float/default.nix b/users/sterni/nix/float/default.nix
new file mode 100644
index 000000000000..ecb6465c8842
--- /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 000000000000..75e2a1bfa091
--- /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 640493083722..81e2f8377f3b 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;