mirror of
https://github.com/roc-lang/roc.git
synced 2025-09-26 13:29:12 +00:00
add trig functions to dec in zig
This commit is contained in:
parent
ab2ec925a3
commit
67494e00fd
2 changed files with 67 additions and 0 deletions
|
@ -44,6 +44,10 @@ pub const RocDec = extern struct {
|
|||
return ret;
|
||||
}
|
||||
|
||||
pub fn toF64(dec: RocDec) f64 {
|
||||
return @intToFloat(f64, dec.num) / comptime @intToFloat(f64, one_point_zero_i128);
|
||||
}
|
||||
|
||||
// TODO: If Str.toDec eventually supports more error types, return errors here.
|
||||
// For now, just return null which will give the default error.
|
||||
pub fn fromStr(roc_str: RocStr) ?RocDec {
|
||||
|
@ -419,6 +423,67 @@ pub const RocDec = extern struct {
|
|||
|
||||
return RocDec{ .num = if (is_answer_negative) -unsigned_answer else unsigned_answer };
|
||||
}
|
||||
|
||||
fn mod2pi(self: RocDec) RocDec {
|
||||
// This is made to be used before calling trig functions that work on the range 0 to 2*pi.
|
||||
// It should be reasonable fast (much faster than calling @mod) and much more accurate as well.
|
||||
// b is 2*pi as a dec. which is 6.2831853071795864769252867665590057684
|
||||
// as dec is times 10^18 so 6283185307179586476.9252867665590057684
|
||||
const b0: u64 = 6283185307179586476;
|
||||
// Fraction that reprensents 64 bits of precision past what dec normally supports.
|
||||
// 0.9252867665590057684 as binary to 64 places.
|
||||
const b1: u64 = 0b1110110011011111100101111111000111001010111000100101011111110111;
|
||||
|
||||
// This is dec/(b0+1), but as a multiplication.
|
||||
// So dec * (1/(b0+1)). This is way faster.
|
||||
const dec = self.num;
|
||||
const tmp = @intCast(i128, num_.mul_u128(math.absCast(dec), 249757942369376157886101012127821356963).hi >> (190 - 128));
|
||||
const q0 = if (dec < 0) -tmp else tmp;
|
||||
|
||||
const upper = q0 * b0;
|
||||
var lower: i128 = undefined;
|
||||
const overflow = @mulWithOverflow(i128, q0, b1, &lower);
|
||||
// TODO: maybe write this out branchlessly.
|
||||
// Currently is is probably cmovs, but could be just math?
|
||||
const q0_sign: i128 =
|
||||
if (q0 > 0) 1 else -1;
|
||||
const overflow_val: i128 = if (overflow) q0_sign << 64 else 0;
|
||||
const full = upper + @intCast(i128, lower >> 64) + overflow_val;
|
||||
|
||||
var out = dec - full;
|
||||
if (out < 0) {
|
||||
out += b0;
|
||||
}
|
||||
|
||||
return RocDec{ .num = out };
|
||||
}
|
||||
|
||||
// I belive the output of the trig functions is always in range of Dec.
|
||||
// If not, we probably should just make it saturate the Dec.
|
||||
// I don't think this should crash or return errors.
|
||||
pub fn sin(self: RocDec) RocDec {
|
||||
return fromF64(math.sin(self.mod2pi().toF64())).?;
|
||||
}
|
||||
|
||||
pub fn cos(self: RocDec) RocDec {
|
||||
return fromF64(math.cos(self.mod2pi().toF64())).?;
|
||||
}
|
||||
|
||||
pub fn tan(self: RocDec) RocDec {
|
||||
return fromF64(math.tan(self.mod2pi().toF64())).?;
|
||||
}
|
||||
|
||||
pub fn asin(self: RocDec) RocDec {
|
||||
return fromF64(math.asin(self.toF64())).?;
|
||||
}
|
||||
|
||||
pub fn acos(self: RocDec) RocDec {
|
||||
return fromF64(math.acos(self.toF64())).?;
|
||||
}
|
||||
|
||||
pub fn atan(self: RocDec) RocDec {
|
||||
return fromF64(math.atan(self.toF64())).?;
|
||||
}
|
||||
};
|
||||
|
||||
// A number has `k` trailling zeros if `10^k` divides into it cleanly
|
||||
|
|
|
@ -22,6 +22,8 @@ comptime {
|
|||
exportDecFn(dec.toStr, "to_str");
|
||||
exportDecFn(dec.fromU64C, "from_u64");
|
||||
exportDecFn(dec.toI128, "to_i128");
|
||||
exportDecFn(dec.fromF64, "from_f64");
|
||||
exportDecFn(dec.toF64, "to_f64");
|
||||
exportDecFn(dec.eqC, "eq");
|
||||
exportDecFn(dec.neqC, "neq");
|
||||
exportDecFn(dec.negateC, "negate");
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue