hare

[hare] The Hare programming language
git clone https://git.torresjrjr.com/hare.git
Log | Files | Refs | README | LICENSE

commit 58382d3280fe347a4a44ee4421de992b67cbe99a
parent 8fa6738f003c8b7d36a4bea7c0c717a9a10f296c
Author: Byron Torres <b@torresjrjr.com>
Date:   Tue, 24 May 2022 04:00:27 +0100

time: add mult()

Signed-off-by: Byron Torres <b@torresjrjr.com>

Diffstat:
Mscripts/gen-stdlib | 6++++--
Mstdlib.mk | 8++++----
Mtime/arithm.ha | 99+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 107 insertions(+), 6 deletions(-)

diff --git a/scripts/gen-stdlib b/scripts/gen-stdlib @@ -1263,13 +1263,15 @@ time() { arithm.ha \ conv.ha \ types.ha - gen_ssa -plinux time linux::vdso + gen_ssa -plinux time \ + linux::vdso math gen_srcs -pfreebsd time \ +freebsd/functions.ha \ arithm.ha \ conv.ha \ types.ha - gen_ssa -pfreebsd time + gen_ssa -pfreebsd time \ + math } time_chrono() { diff --git a/stdlib.mk b/stdlib.mk @@ -1897,7 +1897,7 @@ stdlib_time_linux_srcs = \ $(STDLIB)/time/conv.ha \ $(STDLIB)/time/types.ha -$(HARECACHE)/time/time-linux.ssa: $(stdlib_time_linux_srcs) $(stdlib_rt) $(stdlib_linux_vdso_$(PLATFORM)) +$(HARECACHE)/time/time-linux.ssa: $(stdlib_time_linux_srcs) $(stdlib_rt) $(stdlib_linux_vdso_$(PLATFORM)) $(stdlib_math_$(PLATFORM)) @printf 'HAREC \t$@\n' @mkdir -p $(HARECACHE)/time @HARECACHE=$(HARECACHE) $(HAREC) $(HAREFLAGS) -o $@ -Ntime \ @@ -1910,7 +1910,7 @@ stdlib_time_freebsd_srcs = \ $(STDLIB)/time/conv.ha \ $(STDLIB)/time/types.ha -$(HARECACHE)/time/time-freebsd.ssa: $(stdlib_time_freebsd_srcs) $(stdlib_rt) +$(HARECACHE)/time/time-freebsd.ssa: $(stdlib_time_freebsd_srcs) $(stdlib_rt) $(stdlib_math_$(PLATFORM)) @printf 'HAREC \t$@\n' @mkdir -p $(HARECACHE)/time @HARECACHE=$(HARECACHE) $(HAREC) $(HAREFLAGS) -o $@ -Ntime \ @@ -4066,7 +4066,7 @@ testlib_time_linux_srcs = \ $(STDLIB)/time/conv.ha \ $(STDLIB)/time/types.ha -$(TESTCACHE)/time/time-linux.ssa: $(testlib_time_linux_srcs) $(testlib_rt) $(testlib_linux_vdso_$(PLATFORM)) +$(TESTCACHE)/time/time-linux.ssa: $(testlib_time_linux_srcs) $(testlib_rt) $(testlib_linux_vdso_$(PLATFORM)) $(testlib_math_$(PLATFORM)) @printf 'HAREC \t$@\n' @mkdir -p $(TESTCACHE)/time @HARECACHE=$(TESTCACHE) $(HAREC) $(TESTHAREFLAGS) -o $@ -Ntime \ @@ -4079,7 +4079,7 @@ testlib_time_freebsd_srcs = \ $(STDLIB)/time/conv.ha \ $(STDLIB)/time/types.ha -$(TESTCACHE)/time/time-freebsd.ssa: $(testlib_time_freebsd_srcs) $(testlib_rt) +$(TESTCACHE)/time/time-freebsd.ssa: $(testlib_time_freebsd_srcs) $(testlib_rt) $(testlib_math_$(PLATFORM)) @printf 'HAREC \t$@\n' @mkdir -p $(TESTCACHE)/time @HARECACHE=$(TESTCACHE) $(HAREC) $(TESTHAREFLAGS) -o $@ -Ntime \ diff --git a/time/arithm.ha b/time/arithm.ha @@ -1,6 +1,7 @@ // License: MPL-2.0 // (c) 2022 Byron Torres <b@torresjrjr.com> // (c) 2021 Drew DeVault <sir@cmpwn.com> +use math; // Adds a [[duration]] to an [[instant]], returning an instant further in the // future (given a positive duration), or further in the past (given a negative @@ -36,6 +37,46 @@ export fn compare(a: instant, b: instant) i8 = { else 0; }; +// Scales the given [[instant]]'s scalar value by a factor 'f'. Make sure to +// know what epoch you're dealing with. +export fn mult(a: instant, f: f64) instant = { + // use positive numbers for convenience + const positive = if (a.sec < 0 ^^ f < 0.0) false else true; + const f = if (f < 0.0) -f else f; + const asec: i64 = if (a.sec < 0) -a.sec - 1 else a.sec; + const ansec: i64 = if (a.sec < 0) SECOND - a.nsec else a.nsec; + + // initial multiply + const fsec = (asec: f64 * f); + const bsec = fsec: i64; + const fnsec = (ansec: f64 * f); + const bnsec = fnsec: i64; + + // get seconds overflow (nsec remainder) + const secrem = math::modf64(fsec, 1.0); + const addnsec = (secrem * SECOND: f64): i64; + + // add overflows + const b = instant { + sec = bsec, + nsec = ansec, + }; + const b = add(b, bnsec - ansec); // add nsec overflow + const b = add(b, addnsec); // add sec overflow + + // switch back to original sign + const b = if (positive) { + yield b; + } else { + yield instant { + sec = -b.sec - 1, + nsec = SECOND - b.nsec, + }; + }; + + return b; +}; + @test fn add() void = { const cases = [ // instant a duration d instant b @@ -123,3 +164,61 @@ export fn compare(a: instant, b: instant) i8 = { assert(compare(b, a) > 0); assert(compare(a, a) == 0); }; + +@test fn mult() void = { + const cases = [ + // instant a factor f instant b interpretations + ( 0, 000000000, 000.000, 0, 000000000), // 0.000000000 + ( 9, 000000000, 000.000, 0, 000000000), // 0.000000000 + ( 0, 999999999, 000.000, 0, 000000000), // 0.000000000 + ( 9, 999999999, 000.000, 0, 000000000), // 0.000000000 + + ( 1, 000000000, 001.000, 1, 000000000), // 1.000000000 + ( 9, 000000000, 001.000, 9, 000000000), // 9.000000000 + ( 1, 999999999, 001.000, 1, 999999999), // 1.999999999 + ( 9, 999999999, 001.000, 9, 999999999), // 9.999999999 + + ( 1, 000000000, 000.001, 0, 001000000), // 0.001000000 + ( 1, 000000000, 000.010, 0, 010000000), // 0.010000000 + ( 1, 000000000, 000.100, 0, 100000000), // 0.100000000 + + (-1, 000000000, 000.001, -1, 999000000), // -0.001000000 + (-1, 000000000, 000.010, -1, 990000000), // -0.010000000 + (-1, 000000000, 000.100, -1, 900000000), // -0.100000000 + (-1, 000000000, 001.000, -1, 000000000), // -1.000000000 + + ( 0, 500000000, 000.001, 0, 000500000), // 0.005000000 + ( 0, 500000000, 000.010, 0, 005000000), // 0.050000000 + ( 0, 500000000, 000.100, 0, 050000000), // 0.500000000 + + ( 2, 000000000, 000.001, 0, 002000000), // 0.002000000 + ( 2, 000000000, 000.010, 0, 020000000), // 0.020000000 + ( 2, 000000000, 000.100, 0, 200000000), // 0.200000000 + + ( 3, 141592653, 003.141, 9, 867742523), // 9.867742523073 + ( 2, 718281828, 002.718, 7, 388290007), // 7.388290008504 (rounds down?) + ( 1, 414213562, 001.414, 1, 999697975), // 1.999697976668 (rounds down?) + + ( 3, 141592653, -003.141, -10, 132257477), // -9.867742523073 + ( 2, 718281828, -002.718, -8, 611709993), // -7.388290008504 + ( 1, 414213562, -001.414, -2, 000302025), // -1.999697976668 + + (-4, 858407347, 003.141, -10, 132257477), // -9.867742523073 + (-3, 281718172, 002.718, -8, 611709993), // -7.388290008504 + (-2, 585786438, 001.414, -2, 000302025), // -1.999697976668 + + (-4, 858407347, -003.141, 9, 867742523), // 9.867742523073 + (-3, 281718172, -002.718, 7, 388290007), // 7.388290008504 + (-2, 585786438, -001.414, 1, 999697975), // 1.999697976668 + ]; + + for (let i = 0z; i < len(cases); i += 1) { + const C = cases[i]; + const a = instant { sec = C.0, nsec = C.1 }; + const f = C.2; + const b = instant { sec = C.3, nsec = C.4 }; + const B = mult(a, f); + assert(B.sec == b.sec, "time::mult() .sec error"); + assert(B.nsec == b.nsec, "time::mult() .nsec error"); + }; +};