mirror of
https://github.com/ziglang/zig.git
synced 2026-02-13 04:48:20 +00:00
stage2: implement all builtin floatops for f{16,32,64}
- Merge `floatop.zig` and `floatop_stage1.zig` since most tests now pass on stage2. - Add more behavior tests for a bunch of functions.
This commit is contained in:
parent
44b5fdf326
commit
7f0cf395aa
53
src/Air.zig
53
src/Air.zig
@ -237,9 +237,45 @@ pub const Inst = struct {
|
||||
/// Uses the `ty_op` field.
|
||||
popcount,
|
||||
|
||||
/// Computes the square root of a floating point number.
|
||||
/// Square root of a floating point number.
|
||||
/// Uses the `un_op` field.
|
||||
sqrt,
|
||||
/// Sine a floating point number.
|
||||
/// Uses the `un_op` field.
|
||||
sin,
|
||||
/// Cosine a floating point number.
|
||||
/// Uses the `un_op` field.
|
||||
cos,
|
||||
/// Base e exponential of a floating point number.
|
||||
/// Uses the `un_op` field.
|
||||
exp,
|
||||
/// Base 2 exponential of a floating point number.
|
||||
/// Uses the `un_op` field.
|
||||
exp2,
|
||||
/// Natural (base e) logarithm of a floating point number.
|
||||
/// Uses the `un_op` field.
|
||||
log,
|
||||
/// Base 2 logarithm of a floating point number.
|
||||
/// Uses the `un_op` field.
|
||||
log2,
|
||||
/// Base 10 logarithm of a floating point number.
|
||||
/// Uses the `un_op` field.
|
||||
log10,
|
||||
/// Aboslute value of a floating point number.
|
||||
/// Uses the `un_op` field.
|
||||
fabs,
|
||||
/// Floor: rounds a floating pointer number down to the nearest integer.
|
||||
/// Uses the `un_op` field.
|
||||
floor,
|
||||
/// Ceiling: rounds a floating pointer number up to the nearest integer.
|
||||
/// Uses the `un_op` field.
|
||||
ceil,
|
||||
/// Rounds a floating pointer number to the nearest integer.
|
||||
/// Uses the `un_op` field.
|
||||
round,
|
||||
/// Rounds a floating pointer number to the nearest integer towards zero.
|
||||
/// Uses the `un_op` field.
|
||||
trunc_float,
|
||||
|
||||
/// `<`. Result type is always bool.
|
||||
/// Uses the `bin_op` field.
|
||||
@ -754,7 +790,20 @@ pub fn typeOfIndex(air: Air, inst: Air.Inst.Index) Type {
|
||||
.max,
|
||||
=> return air.typeOf(datas[inst].bin_op.lhs),
|
||||
|
||||
.sqrt => return air.typeOf(datas[inst].un_op),
|
||||
.sqrt,
|
||||
.sin,
|
||||
.cos,
|
||||
.exp,
|
||||
.exp2,
|
||||
.log,
|
||||
.log2,
|
||||
.log10,
|
||||
.fabs,
|
||||
.floor,
|
||||
.ceil,
|
||||
.round,
|
||||
.trunc_float,
|
||||
=> return air.typeOf(datas[inst].un_op),
|
||||
|
||||
.cmp_lt,
|
||||
.cmp_lte,
|
||||
|
||||
@ -339,6 +339,18 @@ fn analyzeInst(
|
||||
.tag_name,
|
||||
.error_name,
|
||||
.sqrt,
|
||||
.sin,
|
||||
.cos,
|
||||
.exp,
|
||||
.exp2,
|
||||
.log,
|
||||
.log2,
|
||||
.log10,
|
||||
.fabs,
|
||||
.floor,
|
||||
.ceil,
|
||||
.round,
|
||||
.trunc_float,
|
||||
=> {
|
||||
const operand = inst_datas[inst].un_op;
|
||||
return trackOperands(a, new_set, inst, main_tomb, .{ operand, .none, .none });
|
||||
|
||||
24
src/Sema.zig
24
src/Sema.zig
@ -747,18 +747,18 @@ fn analyzeBodyInner(
|
||||
.ctz => try sema.zirClzCtz(block, inst, .ctz, Value.ctz),
|
||||
|
||||
.sqrt => try sema.zirUnaryMath(block, inst, .sqrt, Value.sqrt),
|
||||
.sin => @panic("TODO"),
|
||||
.cos => @panic("TODO"),
|
||||
.exp => @panic("TODO"),
|
||||
.exp2 => @panic("TODO"),
|
||||
.log => @panic("TODO"),
|
||||
.log2 => @panic("TODO"),
|
||||
.log10 => @panic("TODO"),
|
||||
.fabs => @panic("TODO"),
|
||||
.floor => @panic("TODO"),
|
||||
.ceil => @panic("TODO"),
|
||||
.trunc => @panic("TODO"),
|
||||
.round => @panic("TODO"),
|
||||
.sin => try sema.zirUnaryMath(block, inst, .sin, Value.sin),
|
||||
.cos => try sema.zirUnaryMath(block, inst, .cos, Value.cos),
|
||||
.exp => try sema.zirUnaryMath(block, inst, .exp, Value.exp),
|
||||
.exp2 => try sema.zirUnaryMath(block, inst, .exp2, Value.exp2),
|
||||
.log => try sema.zirUnaryMath(block, inst, .log, Value.log),
|
||||
.log2 => try sema.zirUnaryMath(block, inst, .log2, Value.log2),
|
||||
.log10 => try sema.zirUnaryMath(block, inst, .log10, Value.log10),
|
||||
.fabs => try sema.zirUnaryMath(block, inst, .fabs, Value.fabs),
|
||||
.floor => try sema.zirUnaryMath(block, inst, .floor, Value.floor),
|
||||
.ceil => try sema.zirUnaryMath(block, inst, .ceil, Value.ceil),
|
||||
.round => try sema.zirUnaryMath(block, inst, .round, Value.round),
|
||||
.trunc => try sema.zirUnaryMath(block, inst, .trunc_float, Value.trunc),
|
||||
|
||||
.error_set_decl => try sema.zirErrorSetDecl(block, inst, .parent),
|
||||
.error_set_decl_anon => try sema.zirErrorSetDecl(block, inst, .anon),
|
||||
|
||||
@ -528,7 +528,20 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
|
||||
.max => try self.airMax(inst),
|
||||
.slice => try self.airSlice(inst),
|
||||
|
||||
.sqrt => try self.airUnaryMath(inst),
|
||||
.sqrt,
|
||||
.sin,
|
||||
.cos,
|
||||
.exp,
|
||||
.exp2,
|
||||
.log,
|
||||
.log2,
|
||||
.log10,
|
||||
.fabs,
|
||||
.floor,
|
||||
.ceil,
|
||||
.round,
|
||||
.trunc_float
|
||||
=> try self.airUnaryMath(inst),
|
||||
|
||||
.add_with_overflow => try self.airAddWithOverflow(inst),
|
||||
.sub_with_overflow => try self.airSubWithOverflow(inst),
|
||||
|
||||
@ -520,7 +520,20 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
|
||||
.max => try self.airMax(inst),
|
||||
.slice => try self.airSlice(inst),
|
||||
|
||||
.sqrt => try self.airUnaryMath(inst),
|
||||
.sqrt,
|
||||
.sin,
|
||||
.cos,
|
||||
.exp,
|
||||
.exp2,
|
||||
.log,
|
||||
.log2,
|
||||
.log10,
|
||||
.fabs,
|
||||
.floor,
|
||||
.ceil,
|
||||
.round,
|
||||
.trunc_float,
|
||||
=> try self.airUnaryMath(inst),
|
||||
|
||||
.add_with_overflow => try self.airAddWithOverflow(inst),
|
||||
.sub_with_overflow => try self.airSubWithOverflow(inst),
|
||||
|
||||
@ -507,7 +507,20 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
|
||||
.max => try self.airMax(inst),
|
||||
.slice => try self.airSlice(inst),
|
||||
|
||||
.sqrt => try self.airUnaryMath(inst),
|
||||
.sqrt,
|
||||
.sin,
|
||||
.cos,
|
||||
.exp,
|
||||
.exp2,
|
||||
.log,
|
||||
.log2,
|
||||
.log10,
|
||||
.fabs,
|
||||
.floor,
|
||||
.ceil,
|
||||
.round,
|
||||
.trunc_float,
|
||||
=> try self.airUnaryMath(inst),
|
||||
|
||||
.add_with_overflow => try self.airAddWithOverflow(inst),
|
||||
.sub_with_overflow => try self.airSubWithOverflow(inst),
|
||||
|
||||
@ -1679,6 +1679,18 @@ fn genInst(self: *Self, inst: Air.Inst.Index) !WValue {
|
||||
.unwrap_errunion_err_ptr,
|
||||
|
||||
.sqrt,
|
||||
.sin,
|
||||
.cos,
|
||||
.exp,
|
||||
.exp2,
|
||||
.log,
|
||||
.log2,
|
||||
.log10,
|
||||
.fabs,
|
||||
.floor,
|
||||
.ceil,
|
||||
.round,
|
||||
.trunc_float,
|
||||
|
||||
.ptr_slice_len_ptr,
|
||||
.ptr_slice_ptr_ptr,
|
||||
|
||||
@ -599,7 +599,20 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
|
||||
.max => try self.airMax(inst),
|
||||
.slice => try self.airSlice(inst),
|
||||
|
||||
.sqrt => try self.airUnaryMath(inst),
|
||||
.sqrt,
|
||||
.sin,
|
||||
.cos,
|
||||
.exp,
|
||||
.exp2,
|
||||
.log,
|
||||
.log2,
|
||||
.log10,
|
||||
.fabs,
|
||||
.floor,
|
||||
.ceil,
|
||||
.round,
|
||||
.trunc_float,
|
||||
=> try self.airUnaryMath(inst),
|
||||
|
||||
.add_with_overflow => try self.airAddWithOverflow(inst),
|
||||
.sub_with_overflow => try self.airSubWithOverflow(inst),
|
||||
|
||||
@ -1446,7 +1446,20 @@ fn genBody(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail, OutO
|
||||
.mul_sat => try airSatOp(f, inst, "muls_"),
|
||||
.shl_sat => try airSatOp(f, inst, "shls_"),
|
||||
|
||||
.sqrt => try airSqrt(f, inst),
|
||||
.sqrt,
|
||||
.sin,
|
||||
.cos,
|
||||
.exp,
|
||||
.exp2,
|
||||
.log,
|
||||
.log2,
|
||||
.log10,
|
||||
.fabs,
|
||||
.floor,
|
||||
.ceil,
|
||||
.round,
|
||||
.trunc_float,
|
||||
=> |tag| return f.fail("TODO: C backend: implement unary op for tag '{s}'", .{@tagName(tag)}),
|
||||
|
||||
.add_with_overflow => try airAddWithOverflow(f, inst),
|
||||
.sub_with_overflow => try airSubWithOverflow(f, inst),
|
||||
@ -3395,12 +3408,6 @@ fn airPrefetch(f: *Function, inst: Air.Inst.Index) !CValue {
|
||||
return CValue.none;
|
||||
}
|
||||
|
||||
fn airSqrt(f: *Function, inst: Air.Inst.Index) !CValue {
|
||||
_ = f;
|
||||
_ = inst;
|
||||
return f.fail("TODO: C backend: implement sqrt", .{});
|
||||
}
|
||||
|
||||
fn toMemoryOrder(order: std.builtin.AtomicOrder) [:0]const u8 {
|
||||
return switch (order) {
|
||||
.Unordered => "memory_order_relaxed",
|
||||
|
||||
@ -2050,7 +2050,19 @@ pub const FuncGen = struct {
|
||||
.shr => try self.airShr(inst, false),
|
||||
.shr_exact => try self.airShr(inst, true),
|
||||
|
||||
.sqrt => try self.airSqrt(inst),
|
||||
.sqrt => try self.airUnaryOp(inst, "llvm.sqrt"),
|
||||
.sin => try self.airUnaryOp(inst, "llvm.sin"),
|
||||
.cos => try self.airUnaryOp(inst, "llvm.cos"),
|
||||
.exp => try self.airUnaryOp(inst, "llvm.exp"),
|
||||
.exp2 => try self.airUnaryOp(inst, "llvm.exp2"),
|
||||
.log => try self.airUnaryOp(inst, "llvm.log"),
|
||||
.log2 => try self.airUnaryOp(inst, "llvm.log2"),
|
||||
.log10 => try self.airUnaryOp(inst, "llvm.log10"),
|
||||
.fabs => try self.airUnaryOp(inst, "llvm.fabs"),
|
||||
.floor => try self.airUnaryOp(inst, "llvm.floor"),
|
||||
.ceil => try self.airUnaryOp(inst, "llvm.ceil"),
|
||||
.round => try self.airUnaryOp(inst, "llvm.round"),
|
||||
.trunc_float => try self.airUnaryOp(inst, "llvm.trunc"),
|
||||
|
||||
.cmp_eq => try self.airCmp(inst, .eq),
|
||||
.cmp_gt => try self.airCmp(inst, .gt),
|
||||
@ -4213,7 +4225,7 @@ pub const FuncGen = struct {
|
||||
}
|
||||
}
|
||||
|
||||
fn airSqrt(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value {
|
||||
fn airUnaryOp(self: *FuncGen, inst: Air.Inst.Index, llvm_fn_name: []const u8) !?*const llvm.Value {
|
||||
if (self.liveness.isUnused(inst)) return null;
|
||||
|
||||
const un_op = self.air.instructions.items(.data)[inst].un_op;
|
||||
@ -4221,7 +4233,7 @@ pub const FuncGen = struct {
|
||||
const operand_ty = self.air.typeOf(un_op);
|
||||
|
||||
const operand_llvm_ty = try self.dg.llvmType(operand_ty);
|
||||
const fn_val = self.getIntrinsic("llvm.sqrt", &.{operand_llvm_ty});
|
||||
const fn_val = self.getIntrinsic(llvm_fn_name, &.{operand_llvm_ty});
|
||||
const params = [_]*const llvm.Value{operand};
|
||||
|
||||
return self.builder.buildCall(fn_val, ¶ms, params.len, .C, .Auto, "");
|
||||
|
||||
@ -159,6 +159,18 @@ const Writer = struct {
|
||||
.tag_name,
|
||||
.error_name,
|
||||
.sqrt,
|
||||
.sin,
|
||||
.cos,
|
||||
.exp,
|
||||
.exp2,
|
||||
.log,
|
||||
.log2,
|
||||
.log10,
|
||||
.fabs,
|
||||
.floor,
|
||||
.ceil,
|
||||
.round,
|
||||
.trunc_float,
|
||||
=> try w.writeUnOp(s, inst),
|
||||
|
||||
.breakpoint,
|
||||
|
||||
384
src/value.zig
384
src/value.zig
@ -3308,6 +3308,390 @@ pub const Value = extern union {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn sin(val: Value, float_type: Type, arena: Allocator, target: Target) Allocator.Error!Value {
|
||||
switch (float_type.floatBits(target)) {
|
||||
16 => {
|
||||
const f = val.toFloat(f16);
|
||||
return Value.Tag.float_16.create(arena, @sin(f));
|
||||
},
|
||||
32 => {
|
||||
const f = val.toFloat(f32);
|
||||
return Value.Tag.float_32.create(arena, @sin(f));
|
||||
},
|
||||
64 => {
|
||||
const f = val.toFloat(f64);
|
||||
return Value.Tag.float_64.create(arena, @sin(f));
|
||||
},
|
||||
80 => {
|
||||
if (true) {
|
||||
@panic("TODO implement compiler_rt sin for f80");
|
||||
}
|
||||
const f = val.toFloat(f80);
|
||||
return Value.Tag.float_80.create(arena, @sin(f));
|
||||
},
|
||||
128 => {
|
||||
if (true) {
|
||||
@panic("TODO implement compiler_rt sin for f128");
|
||||
}
|
||||
const f = val.toFloat(f128);
|
||||
return Value.Tag.float_128.create(arena, @sin(f));
|
||||
},
|
||||
else => unreachable,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn cos(val: Value, float_type: Type, arena: Allocator, target: Target) Allocator.Error!Value {
|
||||
switch (float_type.floatBits(target)) {
|
||||
16 => {
|
||||
const f = val.toFloat(f16);
|
||||
return Value.Tag.float_16.create(arena, @cos(f));
|
||||
},
|
||||
32 => {
|
||||
const f = val.toFloat(f32);
|
||||
return Value.Tag.float_32.create(arena, @cos(f));
|
||||
},
|
||||
64 => {
|
||||
const f = val.toFloat(f64);
|
||||
return Value.Tag.float_64.create(arena, @cos(f));
|
||||
},
|
||||
80 => {
|
||||
if (true) {
|
||||
@panic("TODO implement compiler_rt cos for f80");
|
||||
}
|
||||
const f = val.toFloat(f80);
|
||||
return Value.Tag.float_80.create(arena, @cos(f));
|
||||
},
|
||||
128 => {
|
||||
if (true) {
|
||||
@panic("TODO implement compiler_rt cos for f128");
|
||||
}
|
||||
const f = val.toFloat(f128);
|
||||
return Value.Tag.float_128.create(arena, @cos(f));
|
||||
},
|
||||
else => unreachable,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn exp(val: Value, float_type: Type, arena: Allocator, target: Target) Allocator.Error!Value {
|
||||
switch (float_type.floatBits(target)) {
|
||||
16 => {
|
||||
const f = val.toFloat(f16);
|
||||
return Value.Tag.float_16.create(arena, @exp(f));
|
||||
},
|
||||
32 => {
|
||||
const f = val.toFloat(f32);
|
||||
return Value.Tag.float_32.create(arena, @exp(f));
|
||||
},
|
||||
64 => {
|
||||
const f = val.toFloat(f64);
|
||||
return Value.Tag.float_64.create(arena, @exp(f));
|
||||
},
|
||||
80 => {
|
||||
if (true) {
|
||||
@panic("TODO implement compiler_rt exp for f80");
|
||||
}
|
||||
const f = val.toFloat(f80);
|
||||
return Value.Tag.float_80.create(arena, @exp(f));
|
||||
},
|
||||
128 => {
|
||||
if (true) {
|
||||
@panic("TODO implement compiler_rt exp for f128");
|
||||
}
|
||||
const f = val.toFloat(f128);
|
||||
return Value.Tag.float_128.create(arena, @exp(f));
|
||||
},
|
||||
else => unreachable,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn exp2(val: Value, float_type: Type, arena: Allocator, target: Target) Allocator.Error!Value {
|
||||
switch (float_type.floatBits(target)) {
|
||||
16 => {
|
||||
const f = val.toFloat(f16);
|
||||
return Value.Tag.float_16.create(arena, @exp2(f));
|
||||
},
|
||||
32 => {
|
||||
const f = val.toFloat(f32);
|
||||
return Value.Tag.float_32.create(arena, @exp2(f));
|
||||
},
|
||||
64 => {
|
||||
const f = val.toFloat(f64);
|
||||
return Value.Tag.float_64.create(arena, @exp2(f));
|
||||
},
|
||||
80 => {
|
||||
if (true) {
|
||||
@panic("TODO implement compiler_rt exp2 for f80");
|
||||
}
|
||||
const f = val.toFloat(f80);
|
||||
return Value.Tag.float_80.create(arena, @exp2(f));
|
||||
},
|
||||
128 => {
|
||||
if (true) {
|
||||
@panic("TODO implement compiler_rt exp2 for f128");
|
||||
}
|
||||
const f = val.toFloat(f128);
|
||||
return Value.Tag.float_128.create(arena, @exp2(f));
|
||||
},
|
||||
else => unreachable,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn log(val: Value, float_type: Type, arena: Allocator, target: Target) Allocator.Error!Value {
|
||||
switch (float_type.floatBits(target)) {
|
||||
16 => {
|
||||
const f = val.toFloat(f16);
|
||||
return Value.Tag.float_16.create(arena, @log(f));
|
||||
},
|
||||
32 => {
|
||||
const f = val.toFloat(f32);
|
||||
return Value.Tag.float_32.create(arena, @log(f));
|
||||
},
|
||||
64 => {
|
||||
const f = val.toFloat(f64);
|
||||
return Value.Tag.float_64.create(arena, @log(f));
|
||||
},
|
||||
80 => {
|
||||
if (true) {
|
||||
@panic("TODO implement compiler_rt log for f80");
|
||||
}
|
||||
const f = val.toFloat(f80);
|
||||
return Value.Tag.float_80.create(arena, @log(f));
|
||||
},
|
||||
128 => {
|
||||
if (true) {
|
||||
@panic("TODO implement compiler_rt log for f128");
|
||||
}
|
||||
const f = val.toFloat(f128);
|
||||
return Value.Tag.float_128.create(arena, @log(f));
|
||||
},
|
||||
else => unreachable,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn log2(val: Value, float_type: Type, arena: Allocator, target: Target) Allocator.Error!Value {
|
||||
switch (float_type.floatBits(target)) {
|
||||
16 => {
|
||||
const f = val.toFloat(f16);
|
||||
return Value.Tag.float_16.create(arena, @log2(f));
|
||||
},
|
||||
32 => {
|
||||
const f = val.toFloat(f32);
|
||||
return Value.Tag.float_32.create(arena, @log2(f));
|
||||
},
|
||||
64 => {
|
||||
const f = val.toFloat(f64);
|
||||
return Value.Tag.float_64.create(arena, @log2(f));
|
||||
},
|
||||
80 => {
|
||||
if (true) {
|
||||
@panic("TODO implement compiler_rt log2 for f80");
|
||||
}
|
||||
const f = val.toFloat(f80);
|
||||
return Value.Tag.float_80.create(arena, @log2(f));
|
||||
},
|
||||
128 => {
|
||||
if (true) {
|
||||
@panic("TODO implement compiler_rt log2 for f128");
|
||||
}
|
||||
const f = val.toFloat(f128);
|
||||
return Value.Tag.float_128.create(arena, @log2(f));
|
||||
},
|
||||
else => unreachable,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn log10(val: Value, float_type: Type, arena: Allocator, target: Target) Allocator.Error!Value {
|
||||
switch (float_type.floatBits(target)) {
|
||||
16 => {
|
||||
const f = val.toFloat(f16);
|
||||
return Value.Tag.float_16.create(arena, @log10(f));
|
||||
},
|
||||
32 => {
|
||||
const f = val.toFloat(f32);
|
||||
return Value.Tag.float_32.create(arena, @log10(f));
|
||||
},
|
||||
64 => {
|
||||
const f = val.toFloat(f64);
|
||||
return Value.Tag.float_64.create(arena, @log10(f));
|
||||
},
|
||||
80 => {
|
||||
if (true) {
|
||||
@panic("TODO implement compiler_rt log10 for f80");
|
||||
}
|
||||
const f = val.toFloat(f80);
|
||||
return Value.Tag.float_80.create(arena, @log10(f));
|
||||
},
|
||||
128 => {
|
||||
if (true) {
|
||||
@panic("TODO implement compiler_rt log10 for f128");
|
||||
}
|
||||
const f = val.toFloat(f128);
|
||||
return Value.Tag.float_128.create(arena, @log10(f));
|
||||
},
|
||||
else => unreachable,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn fabs(val: Value, float_type: Type, arena: Allocator, target: Target) Allocator.Error!Value {
|
||||
switch (float_type.floatBits(target)) {
|
||||
16 => {
|
||||
const f = val.toFloat(f16);
|
||||
return Value.Tag.float_16.create(arena, @fabs(f));
|
||||
},
|
||||
32 => {
|
||||
const f = val.toFloat(f32);
|
||||
return Value.Tag.float_32.create(arena, @fabs(f));
|
||||
},
|
||||
64 => {
|
||||
const f = val.toFloat(f64);
|
||||
return Value.Tag.float_64.create(arena, @fabs(f));
|
||||
},
|
||||
80 => {
|
||||
if (true) {
|
||||
@panic("TODO implement compiler_rt fabs for f80");
|
||||
}
|
||||
const f = val.toFloat(f80);
|
||||
return Value.Tag.float_80.create(arena, @fabs(f));
|
||||
},
|
||||
128 => {
|
||||
if (true) {
|
||||
@panic("TODO implement compiler_rt fabs for f128");
|
||||
}
|
||||
const f = val.toFloat(f128);
|
||||
return Value.Tag.float_128.create(arena, @fabs(f));
|
||||
},
|
||||
else => unreachable,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn floor(val: Value, float_type: Type, arena: Allocator, target: Target) Allocator.Error!Value {
|
||||
switch (float_type.floatBits(target)) {
|
||||
16 => {
|
||||
const f = val.toFloat(f16);
|
||||
return Value.Tag.float_16.create(arena, @floor(f));
|
||||
},
|
||||
32 => {
|
||||
const f = val.toFloat(f32);
|
||||
return Value.Tag.float_32.create(arena, @floor(f));
|
||||
},
|
||||
64 => {
|
||||
const f = val.toFloat(f64);
|
||||
return Value.Tag.float_64.create(arena, @floor(f));
|
||||
},
|
||||
80 => {
|
||||
if (true) {
|
||||
@panic("TODO implement compiler_rt floor for f80");
|
||||
}
|
||||
const f = val.toFloat(f80);
|
||||
return Value.Tag.float_80.create(arena, @floor(f));
|
||||
},
|
||||
128 => {
|
||||
if (true) {
|
||||
@panic("TODO implement compiler_rt floor for f128");
|
||||
}
|
||||
const f = val.toFloat(f128);
|
||||
return Value.Tag.float_128.create(arena, @floor(f));
|
||||
},
|
||||
else => unreachable,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn ceil(val: Value, float_type: Type, arena: Allocator, target: Target) Allocator.Error!Value {
|
||||
switch (float_type.floatBits(target)) {
|
||||
16 => {
|
||||
const f = val.toFloat(f16);
|
||||
return Value.Tag.float_16.create(arena, @ceil(f));
|
||||
},
|
||||
32 => {
|
||||
const f = val.toFloat(f32);
|
||||
return Value.Tag.float_32.create(arena, @ceil(f));
|
||||
},
|
||||
64 => {
|
||||
const f = val.toFloat(f64);
|
||||
return Value.Tag.float_64.create(arena, @ceil(f));
|
||||
},
|
||||
80 => {
|
||||
if (true) {
|
||||
@panic("TODO implement compiler_rt ceil for f80");
|
||||
}
|
||||
const f = val.toFloat(f80);
|
||||
return Value.Tag.float_80.create(arena, @ceil(f));
|
||||
},
|
||||
128 => {
|
||||
if (true) {
|
||||
@panic("TODO implement compiler_rt ceil for f128");
|
||||
}
|
||||
const f = val.toFloat(f128);
|
||||
return Value.Tag.float_128.create(arena, @ceil(f));
|
||||
},
|
||||
else => unreachable,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn round(val: Value, float_type: Type, arena: Allocator, target: Target) Allocator.Error!Value {
|
||||
switch (float_type.floatBits(target)) {
|
||||
16 => {
|
||||
const f = val.toFloat(f16);
|
||||
return Value.Tag.float_16.create(arena, @round(f));
|
||||
},
|
||||
32 => {
|
||||
const f = val.toFloat(f32);
|
||||
return Value.Tag.float_32.create(arena, @round(f));
|
||||
},
|
||||
64 => {
|
||||
const f = val.toFloat(f64);
|
||||
return Value.Tag.float_64.create(arena, @round(f));
|
||||
},
|
||||
80 => {
|
||||
if (true) {
|
||||
@panic("TODO implement compiler_rt round for f80");
|
||||
}
|
||||
const f = val.toFloat(f80);
|
||||
return Value.Tag.float_80.create(arena, @round(f));
|
||||
},
|
||||
128 => {
|
||||
if (true) {
|
||||
@panic("TODO implement compiler_rt round for f128");
|
||||
}
|
||||
const f = val.toFloat(f128);
|
||||
return Value.Tag.float_128.create(arena, @round(f));
|
||||
},
|
||||
else => unreachable,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn trunc(val: Value, float_type: Type, arena: Allocator, target: Target) Allocator.Error!Value {
|
||||
switch (float_type.floatBits(target)) {
|
||||
16 => {
|
||||
const f = val.toFloat(f16);
|
||||
return Value.Tag.float_16.create(arena, @trunc(f));
|
||||
},
|
||||
32 => {
|
||||
const f = val.toFloat(f32);
|
||||
return Value.Tag.float_32.create(arena, @trunc(f));
|
||||
},
|
||||
64 => {
|
||||
const f = val.toFloat(f64);
|
||||
return Value.Tag.float_64.create(arena, @trunc(f));
|
||||
},
|
||||
80 => {
|
||||
if (true) {
|
||||
@panic("TODO implement compiler_rt trunc for f80");
|
||||
}
|
||||
const f = val.toFloat(f80);
|
||||
return Value.Tag.float_80.create(arena, @trunc(f));
|
||||
},
|
||||
128 => {
|
||||
if (true) {
|
||||
@panic("TODO implement compiler_rt trunc for f128");
|
||||
}
|
||||
const f = val.toFloat(f128);
|
||||
return Value.Tag.float_128.create(arena, @trunc(f));
|
||||
},
|
||||
else => unreachable,
|
||||
}
|
||||
}
|
||||
|
||||
/// This type is not copyable since it may contain pointers to its inner data.
|
||||
pub const Payload = struct {
|
||||
tag: Tag,
|
||||
|
||||
@ -150,7 +150,6 @@ test {
|
||||
_ = @import("behavior/const_slice_child.zig");
|
||||
_ = @import("behavior/export_self_referential_type_info.zig");
|
||||
_ = @import("behavior/field_parent_ptr.zig");
|
||||
_ = @import("behavior/floatop_stage1.zig");
|
||||
_ = @import("behavior/fn_delegation.zig");
|
||||
_ = @import("behavior/ir_block_deps.zig");
|
||||
_ = @import("behavior/misc.zig");
|
||||
|
||||
@ -1,12 +1,22 @@
|
||||
const std = @import("std");
|
||||
const builtin = @import("builtin");
|
||||
const expect = std.testing.expect;
|
||||
const math = std.math;
|
||||
const pi = std.math.pi;
|
||||
const e = std.math.e;
|
||||
const Vector = std.meta.Vector;
|
||||
const has_f80_rt = @import("builtin").cpu.arch == .x86_64;
|
||||
|
||||
const epsilon_16 = 0.001;
|
||||
const epsilon = 0.000001;
|
||||
|
||||
fn epsForType(comptime T: type) T {
|
||||
return switch (T) {
|
||||
f16 => @as(f16, epsilon_16),
|
||||
else => @as(T, epsilon),
|
||||
};
|
||||
}
|
||||
|
||||
test "floating point comparisons" {
|
||||
try testFloatComparisons();
|
||||
comptime try testFloatComparisons();
|
||||
@ -79,19 +89,37 @@ test "@sqrt" {
|
||||
}
|
||||
|
||||
fn testSqrt() !void {
|
||||
{
|
||||
var a: f16 = 4;
|
||||
try expect(@sqrt(a) == 2);
|
||||
}
|
||||
{
|
||||
var a: f32 = 9;
|
||||
try expect(@sqrt(a) == 3);
|
||||
var b: f32 = 1.1;
|
||||
try expect(math.approxEqAbs(f32, @sqrt(b), 1.0488088481701516, epsilon));
|
||||
}
|
||||
{
|
||||
var a: f64 = 25;
|
||||
try expect(@sqrt(a) == 5);
|
||||
try expect(@sqrt(@as(f16, 4)) == 2);
|
||||
try expect(@sqrt(@as(f32, 9)) == 3);
|
||||
try expect(@sqrt(@as(f64, 25)) == 5);
|
||||
try expect(math.approxEqAbs(f32, @sqrt(@as(f32, 1.1)), 1.0488088481701516, epsilon));
|
||||
try expect(math.approxEqAbs(f32, @sqrt(@as(f32, 2.0)), 1.4142135623730950, epsilon));
|
||||
|
||||
if (builtin.zig_backend == .stage1) {
|
||||
if (has_f80_rt) {
|
||||
var a: f80 = 25;
|
||||
try expect(@sqrt(a) == 5);
|
||||
}
|
||||
{
|
||||
const a: comptime_float = 25.0;
|
||||
try expect(@sqrt(a) == 5.0);
|
||||
}
|
||||
// TODO test f128, and c_longdouble
|
||||
// https://github.com/ziglang/zig/issues/4026
|
||||
//{
|
||||
// var a: f128 = 49;
|
||||
//try expect(@sqrt(a) == 7);
|
||||
//}
|
||||
|
||||
// TODO Implement Vector support for stage2
|
||||
{
|
||||
var v: Vector(4, f32) = [_]f32{ 1.1, 2.2, 3.3, 4.4 };
|
||||
var result = @sqrt(v);
|
||||
try expect(math.approxEqAbs(f32, @sqrt(@as(f32, 1.1)), result[0], epsilon));
|
||||
try expect(math.approxEqAbs(f32, @sqrt(@as(f32, 2.2)), result[1], epsilon));
|
||||
try expect(math.approxEqAbs(f32, @sqrt(@as(f32, 3.3)), result[2], epsilon));
|
||||
try expect(math.approxEqAbs(f32, @sqrt(@as(f32, 4.4)), result[3], epsilon));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -114,3 +142,311 @@ test "more @sqrt f16 tests" {
|
||||
try expect(math.isNan(@sqrt(@as(f16, -1.0))));
|
||||
try expect(math.isNan(@sqrt(@as(f16, math.nan(f16)))));
|
||||
}
|
||||
|
||||
test "@sin" {
|
||||
comptime try testSin();
|
||||
try testSin();
|
||||
}
|
||||
|
||||
fn testSin() !void {
|
||||
// TODO: Implement Vector support for other backends
|
||||
if (builtin.zig_backend == .stage1) {
|
||||
var v: Vector(4, f32) = [_]f32{ 1.1, 2.2, 3.3, 4.4 };
|
||||
var result = @sin(v);
|
||||
try expect(math.approxEqAbs(f32, @sin(@as(f32, 1.1)), result[0], epsilon));
|
||||
try expect(math.approxEqAbs(f32, @sin(@as(f32, 2.2)), result[1], epsilon));
|
||||
try expect(math.approxEqAbs(f32, @sin(@as(f32, 3.3)), result[2], epsilon));
|
||||
try expect(math.approxEqAbs(f32, @sin(@as(f32, 4.4)), result[3], epsilon));
|
||||
|
||||
// stage1 emits an incorrect compile error for `@as(ty, std.math.pi / 2)`
|
||||
// so skip the rest of the tests.
|
||||
return;
|
||||
}
|
||||
|
||||
inline for ([_]type{ f16, f32, f64 }) |ty| {
|
||||
const eps = epsForType(ty);
|
||||
try expect(@sin(@as(ty, 0)) == 0);
|
||||
try expect(math.approxEqAbs(ty, @sin(@as(ty, std.math.pi)), 0, eps));
|
||||
try expect(math.approxEqAbs(ty, @sin(@as(ty, std.math.pi / 2)), 1, eps));
|
||||
try expect(math.approxEqAbs(ty, @sin(@as(ty, std.math.pi / 4)), 0.7071067811865475, eps));
|
||||
}
|
||||
}
|
||||
|
||||
test "@cos" {
|
||||
comptime try testCos();
|
||||
try testCos();
|
||||
}
|
||||
|
||||
fn testCos() !void {
|
||||
// TODO: Implement Vector support for other backends
|
||||
if (builtin.zig_backend == .stage1) {
|
||||
var v: Vector(4, f32) = [_]f32{ 1.1, 2.2, 3.3, 4.4 };
|
||||
var result = @cos(v);
|
||||
try expect(math.approxEqAbs(f32, @cos(@as(f32, 1.1)), result[0], epsilon));
|
||||
try expect(math.approxEqAbs(f32, @cos(@as(f32, 2.2)), result[1], epsilon));
|
||||
try expect(math.approxEqAbs(f32, @cos(@as(f32, 3.3)), result[2], epsilon));
|
||||
try expect(math.approxEqAbs(f32, @cos(@as(f32, 4.4)), result[3], epsilon));
|
||||
|
||||
// stage1 emits an incorrect compile error for `@as(ty, std.math.pi / 2)`
|
||||
// so skip the rest of the tests.
|
||||
return;
|
||||
}
|
||||
|
||||
inline for ([_]type{ f16, f32, f64 }) |ty| {
|
||||
const eps = epsForType(ty);
|
||||
try expect(@cos(@as(ty, 0)) == 1);
|
||||
try expect(math.approxEqAbs(ty, @cos(@as(ty, std.math.pi)), -1, eps));
|
||||
try expect(math.approxEqAbs(ty, @cos(@as(ty, std.math.pi / 2)), 0, eps));
|
||||
try expect(math.approxEqAbs(ty, @cos(@as(ty, std.math.pi / 4)), 0.7071067811865475, eps));
|
||||
}
|
||||
}
|
||||
|
||||
test "@exp" {
|
||||
comptime try testExp();
|
||||
try testExp();
|
||||
}
|
||||
|
||||
fn testExp() !void {
|
||||
inline for ([_]type{ f16, f32, f64 }) |ty| {
|
||||
const eps = epsForType(ty);
|
||||
try expect(@exp(@as(ty, 0)) == 1);
|
||||
try expect(math.approxEqAbs(ty, @exp(@as(ty, 2)), 7.389056098930650, eps));
|
||||
try expect(math.approxEqAbs(ty, @exp(@as(ty, 5)), 148.4131591025766, eps));
|
||||
}
|
||||
|
||||
// TODO: Implement Vector support for other backends
|
||||
if (builtin.zig_backend == .stage1) {
|
||||
var v: Vector(4, f32) = [_]f32{ 1.1, 2.2, 0.3, 0.4 };
|
||||
var result = @exp(v);
|
||||
try expect(math.approxEqAbs(f32, @exp(@as(f32, 1.1)), result[0], epsilon));
|
||||
try expect(math.approxEqAbs(f32, @exp(@as(f32, 2.2)), result[1], epsilon));
|
||||
try expect(math.approxEqAbs(f32, @exp(@as(f32, 0.3)), result[2], epsilon));
|
||||
try expect(math.approxEqAbs(f32, @exp(@as(f32, 0.4)), result[3], epsilon));
|
||||
}
|
||||
}
|
||||
|
||||
test "@exp2" {
|
||||
comptime try testExp2();
|
||||
try testExp2();
|
||||
}
|
||||
|
||||
fn testExp2() !void {
|
||||
inline for ([_]type{ f16, f32, f64 }) |ty| {
|
||||
const eps = epsForType(ty);
|
||||
try expect(@exp2(@as(ty, 2)) == 4);
|
||||
try expect(math.approxEqAbs(ty, @exp2(@as(ty, 1.5)), 2.8284271247462, eps));
|
||||
try expect(math.approxEqAbs(ty, @exp2(@as(ty, 4.5)), 22.627416997969, eps));
|
||||
}
|
||||
|
||||
// TODO: Implement Vector support for other backends
|
||||
if (builtin.zig_backend == .stage1) {
|
||||
var v: Vector(4, f32) = [_]f32{ 1.1, 2.2, 0.3, 0.4 };
|
||||
var result = @exp2(v);
|
||||
try expect(math.approxEqAbs(f32, @exp2(@as(f32, 1.1)), result[0], epsilon));
|
||||
try expect(math.approxEqAbs(f32, @exp2(@as(f32, 2.2)), result[1], epsilon));
|
||||
try expect(math.approxEqAbs(f32, @exp2(@as(f32, 0.3)), result[2], epsilon));
|
||||
try expect(math.approxEqAbs(f32, @exp2(@as(f32, 0.4)), result[3], epsilon));
|
||||
}
|
||||
}
|
||||
|
||||
test "@log" {
|
||||
// Old musl (and glibc?), and our current math.ln implementation do not return 1
|
||||
// so also accept those values.
|
||||
comptime try testLog();
|
||||
try testLog();
|
||||
}
|
||||
|
||||
fn testLog() !void {
|
||||
{
|
||||
var a: f16 = e;
|
||||
try expect(math.approxEqAbs(f16, @log(a), 1, epsilon));
|
||||
}
|
||||
{
|
||||
var a: f32 = e;
|
||||
try expect(@log(a) == 1 or @log(a) == @bitCast(f32, @as(u32, 0x3f7fffff)));
|
||||
}
|
||||
{
|
||||
var a: f64 = e;
|
||||
try expect(@log(a) == 1 or @log(a) == @bitCast(f64, @as(u64, 0x3ff0000000000000)));
|
||||
}
|
||||
inline for ([_]type{ f16, f32, f64 }) |ty| {
|
||||
const eps = epsForType(ty);
|
||||
try expect(math.approxEqAbs(ty, @log(@as(ty, 2)), 0.6931471805599, eps));
|
||||
try expect(math.approxEqAbs(ty, @log(@as(ty, 5)), 1.6094379124341, eps));
|
||||
}
|
||||
|
||||
// TODO: Implement Vector support for other backends
|
||||
if (builtin.zig_backend == .stage1) {
|
||||
var v: Vector(4, f32) = [_]f32{ 1.1, 2.2, 0.3, 0.4 };
|
||||
var result = @log(v);
|
||||
try expect(math.approxEqAbs(f32, @log(@as(f32, 1.1)), result[0], epsilon));
|
||||
try expect(math.approxEqAbs(f32, @log(@as(f32, 2.2)), result[1], epsilon));
|
||||
try expect(math.approxEqAbs(f32, @log(@as(f32, 0.3)), result[2], epsilon));
|
||||
try expect(math.approxEqAbs(f32, @log(@as(f32, 0.4)), result[3], epsilon));
|
||||
}
|
||||
}
|
||||
|
||||
test "@log2" {
|
||||
comptime try testLog2();
|
||||
try testLog2();
|
||||
}
|
||||
|
||||
fn testLog2() !void {
|
||||
inline for ([_]type{ f16, f32, f64 }) |ty| {
|
||||
const eps = epsForType(ty);
|
||||
try expect(@log2(@as(ty, 4)) == 2);
|
||||
try expect(math.approxEqAbs(ty, @log2(@as(ty, 6)), 2.5849625007212, eps));
|
||||
try expect(math.approxEqAbs(ty, @log2(@as(ty, 10)), 3.3219280948874, eps));
|
||||
}
|
||||
|
||||
// TODO: Implement Vector support for other backends
|
||||
if (builtin.zig_backend == .stage1) {
|
||||
var v: Vector(4, f32) = [_]f32{ 1.1, 2.2, 0.3, 0.4 };
|
||||
var result = @log2(v);
|
||||
try expect(math.approxEqAbs(f32, @log2(@as(f32, 1.1)), result[0], epsilon));
|
||||
try expect(math.approxEqAbs(f32, @log2(@as(f32, 2.2)), result[1], epsilon));
|
||||
try expect(math.approxEqAbs(f32, @log2(@as(f32, 0.3)), result[2], epsilon));
|
||||
try expect(math.approxEqAbs(f32, @log2(@as(f32, 0.4)), result[3], epsilon));
|
||||
}
|
||||
}
|
||||
|
||||
test "@log10" {
|
||||
comptime try testLog10();
|
||||
try testLog10();
|
||||
}
|
||||
|
||||
fn testLog10() !void {
|
||||
inline for ([_]type{ f16, f32, f64 }) |ty| {
|
||||
const eps = epsForType(ty);
|
||||
try expect(@log10(@as(ty, 100)) == 2);
|
||||
try expect(math.approxEqAbs(ty, @log10(@as(ty, 15)), 1.176091259056, eps));
|
||||
try expect(math.approxEqAbs(ty, @log10(@as(ty, 50)), 1.698970004336, eps));
|
||||
}
|
||||
|
||||
// TODO: Implement Vector support for other backends
|
||||
if (builtin.zig_backend == .stage1) {
|
||||
var v: Vector(4, f32) = [_]f32{ 1.1, 2.2, 0.3, 0.4 };
|
||||
var result = @log10(v);
|
||||
try expect(math.approxEqAbs(f32, @log10(@as(f32, 1.1)), result[0], epsilon));
|
||||
try expect(math.approxEqAbs(f32, @log10(@as(f32, 2.2)), result[1], epsilon));
|
||||
try expect(math.approxEqAbs(f32, @log10(@as(f32, 0.3)), result[2], epsilon));
|
||||
try expect(math.approxEqAbs(f32, @log10(@as(f32, 0.4)), result[3], epsilon));
|
||||
}
|
||||
}
|
||||
|
||||
test "@fabs" {
|
||||
comptime try testFabs();
|
||||
try testFabs();
|
||||
}
|
||||
|
||||
fn testFabs() !void {
|
||||
try expect(@fabs(@as(f16, -2.5)) == 2.5);
|
||||
try expect(@fabs(@as(f16, 2.5)) == 2.5);
|
||||
try expect(@fabs(@as(f32, -2.5)) == 2.5);
|
||||
try expect(@fabs(@as(f32, 2.5)) == 2.5);
|
||||
try expect(@fabs(@as(f64, -2.5)) == 2.5);
|
||||
try expect(@fabs(@as(f64, 2.5)) == 2.5);
|
||||
|
||||
// TODO test f128, and c_longdouble
|
||||
// https://github.com/ziglang/zig/issues/4026
|
||||
// {
|
||||
// var a: f80 = -2.5;
|
||||
// var b: f80 = 2.5;
|
||||
// try expect(@fabs(a) == 2.5);
|
||||
// try expect(@fabs(b) == 2.5);
|
||||
// }
|
||||
|
||||
// TODO: Implement Vector support for other backends
|
||||
if (builtin.zig_backend == .stage1) {
|
||||
var v: Vector(4, f32) = [_]f32{ 1.1, -2.2, 0.3, -0.4 };
|
||||
var result = @fabs(v);
|
||||
try expect(math.approxEqAbs(f32, @fabs(@as(f32, 1.1)), result[0], epsilon));
|
||||
try expect(math.approxEqAbs(f32, @fabs(@as(f32, -2.2)), result[1], epsilon));
|
||||
try expect(math.approxEqAbs(f32, @fabs(@as(f32, 0.3)), result[2], epsilon));
|
||||
try expect(math.approxEqAbs(f32, @fabs(@as(f32, -0.4)), result[3], epsilon));
|
||||
}
|
||||
}
|
||||
|
||||
test "@floor" {
|
||||
comptime try testFloor();
|
||||
try testFloor();
|
||||
}
|
||||
|
||||
fn testFloor() !void {
|
||||
try expect(@floor(@as(f16, 2.1)) == 2);
|
||||
try expect(@floor(@as(f32, 2.1)) == 2);
|
||||
try expect(@floor(@as(f64, 3.5)) == 3);
|
||||
|
||||
// TODO test f128, and c_longdouble
|
||||
// https://github.com/ziglang/zig/issues/4026
|
||||
// {
|
||||
// var a: f80 = 3.5;
|
||||
// try expect(@floor(a) == 3);
|
||||
// }
|
||||
|
||||
// TODO: Implement Vector support for other backends
|
||||
if (builtin.zig_backend == .stage1) {
|
||||
var v: Vector(4, f32) = [_]f32{ 1.1, -2.2, 0.3, -0.4 };
|
||||
var result = @floor(v);
|
||||
try expect(math.approxEqAbs(f32, @floor(@as(f32, 1.1)), result[0], epsilon));
|
||||
try expect(math.approxEqAbs(f32, @floor(@as(f32, -2.2)), result[1], epsilon));
|
||||
try expect(math.approxEqAbs(f32, @floor(@as(f32, 0.3)), result[2], epsilon));
|
||||
try expect(math.approxEqAbs(f32, @floor(@as(f32, -0.4)), result[3], epsilon));
|
||||
}
|
||||
}
|
||||
|
||||
test "@ceil" {
|
||||
comptime try testCeil();
|
||||
try testCeil();
|
||||
}
|
||||
|
||||
fn testCeil() !void {
|
||||
try expect(@ceil(@as(f16, 2.1)) == 3);
|
||||
try expect(@ceil(@as(f32, 2.1)) == 3);
|
||||
try expect(@ceil(@as(f64, 3.5)) == 4);
|
||||
|
||||
// TODO test f128, and c_longdouble
|
||||
// https://github.com/ziglang/zig/issues/4026
|
||||
// {
|
||||
// var a: f80 = 3.5;
|
||||
// try expect(@ceil(a) == 4);
|
||||
// }
|
||||
|
||||
// TODO: Implement Vector support for other backends
|
||||
if (builtin.zig_backend == .stage1) {
|
||||
var v: Vector(4, f32) = [_]f32{ 1.1, -2.2, 0.3, -0.4 };
|
||||
var result = @ceil(v);
|
||||
try expect(math.approxEqAbs(f32, @ceil(@as(f32, 1.1)), result[0], epsilon));
|
||||
try expect(math.approxEqAbs(f32, @ceil(@as(f32, -2.2)), result[1], epsilon));
|
||||
try expect(math.approxEqAbs(f32, @ceil(@as(f32, 0.3)), result[2], epsilon));
|
||||
try expect(math.approxEqAbs(f32, @ceil(@as(f32, -0.4)), result[3], epsilon));
|
||||
}
|
||||
}
|
||||
|
||||
test "@trunc" {
|
||||
comptime try testTrunc();
|
||||
try testTrunc();
|
||||
}
|
||||
|
||||
fn testTrunc() !void {
|
||||
try expect(@trunc(@as(f16, 2.1)) == 2);
|
||||
try expect(@trunc(@as(f32, 2.1)) == 2);
|
||||
try expect(@trunc(@as(f64, -3.5)) == -3);
|
||||
|
||||
// TODO test f128, and c_longdouble
|
||||
// https://github.com/ziglang/zig/issues/4026
|
||||
// {
|
||||
// var a: f80 = -3.5;
|
||||
// try expect(@trunc(a) == -3);
|
||||
// }
|
||||
|
||||
// TODO: Implement Vector support for other backends
|
||||
if (builtin.zig_backend == .stage1) {
|
||||
var v: Vector(4, f32) = [_]f32{ 1.1, -2.2, 0.3, -0.4 };
|
||||
var result = @trunc(v);
|
||||
try expect(math.approxEqAbs(f32, @trunc(@as(f32, 1.1)), result[0], epsilon));
|
||||
try expect(math.approxEqAbs(f32, @trunc(@as(f32, -2.2)), result[1], epsilon));
|
||||
try expect(math.approxEqAbs(f32, @trunc(@as(f32, 0.3)), result[2], epsilon));
|
||||
try expect(math.approxEqAbs(f32, @trunc(@as(f32, -0.4)), result[3], epsilon));
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,452 +0,0 @@
|
||||
const std = @import("std");
|
||||
const expect = std.testing.expect;
|
||||
const math = std.math;
|
||||
const pi = std.math.pi;
|
||||
const e = std.math.e;
|
||||
const Vector = std.meta.Vector;
|
||||
const has_f80_rt = @import("builtin").cpu.arch == .x86_64;
|
||||
|
||||
const epsilon = 0.000001;
|
||||
|
||||
test "@sqrt" {
|
||||
comptime try testSqrt();
|
||||
try testSqrt();
|
||||
}
|
||||
|
||||
fn testSqrt() !void {
|
||||
if (has_f80_rt) {
|
||||
var a: f80 = 25;
|
||||
try expect(@sqrt(a) == 5);
|
||||
}
|
||||
{
|
||||
const a: comptime_float = 25.0;
|
||||
try expect(@sqrt(a) == 5.0);
|
||||
}
|
||||
// TODO https://github.com/ziglang/zig/issues/4026
|
||||
//{
|
||||
// var a: f128 = 49;
|
||||
//try expect(@sqrt(a) == 7);
|
||||
//}
|
||||
{
|
||||
var v: Vector(4, f32) = [_]f32{ 1.1, 2.2, 3.3, 4.4 };
|
||||
var result = @sqrt(v);
|
||||
try expect(math.approxEqAbs(f32, @sqrt(@as(f32, 1.1)), result[0], epsilon));
|
||||
try expect(math.approxEqAbs(f32, @sqrt(@as(f32, 2.2)), result[1], epsilon));
|
||||
try expect(math.approxEqAbs(f32, @sqrt(@as(f32, 3.3)), result[2], epsilon));
|
||||
try expect(math.approxEqAbs(f32, @sqrt(@as(f32, 4.4)), result[3], epsilon));
|
||||
}
|
||||
}
|
||||
|
||||
test "@sin" {
|
||||
comptime try testSin();
|
||||
try testSin();
|
||||
}
|
||||
|
||||
fn testSin() !void {
|
||||
// TODO test f128, and c_longdouble
|
||||
// https://github.com/ziglang/zig/issues/4026
|
||||
{
|
||||
var a: f16 = 0;
|
||||
try expect(@sin(a) == 0);
|
||||
}
|
||||
{
|
||||
var a: f32 = 0;
|
||||
try expect(@sin(a) == 0);
|
||||
}
|
||||
{
|
||||
var a: f64 = 0;
|
||||
try expect(@sin(a) == 0);
|
||||
}
|
||||
// {
|
||||
// var a: f80 = 0;
|
||||
// try expect(@sin(a) == 0);
|
||||
// }
|
||||
{
|
||||
var v: Vector(4, f32) = [_]f32{ 1.1, 2.2, 3.3, 4.4 };
|
||||
var result = @sin(v);
|
||||
try expect(math.approxEqAbs(f32, @sin(@as(f32, 1.1)), result[0], epsilon));
|
||||
try expect(math.approxEqAbs(f32, @sin(@as(f32, 2.2)), result[1], epsilon));
|
||||
try expect(math.approxEqAbs(f32, @sin(@as(f32, 3.3)), result[2], epsilon));
|
||||
try expect(math.approxEqAbs(f32, @sin(@as(f32, 4.4)), result[3], epsilon));
|
||||
}
|
||||
}
|
||||
|
||||
test "@cos" {
|
||||
comptime try testCos();
|
||||
try testCos();
|
||||
}
|
||||
|
||||
fn testCos() !void {
|
||||
// TODO test f128, and c_longdouble
|
||||
// https://github.com/ziglang/zig/issues/4026
|
||||
{
|
||||
var a: f16 = 0;
|
||||
try expect(@cos(a) == 1);
|
||||
}
|
||||
{
|
||||
var a: f32 = 0;
|
||||
try expect(@cos(a) == 1);
|
||||
}
|
||||
{
|
||||
var a: f64 = 0;
|
||||
try expect(@cos(a) == 1);
|
||||
}
|
||||
// {
|
||||
// var a: f80 = 0;
|
||||
// try expect(@cos(a) == 1);
|
||||
// }
|
||||
{
|
||||
var v: Vector(4, f32) = [_]f32{ 1.1, 2.2, 3.3, 4.4 };
|
||||
var result = @cos(v);
|
||||
try expect(math.approxEqAbs(f32, @cos(@as(f32, 1.1)), result[0], epsilon));
|
||||
try expect(math.approxEqAbs(f32, @cos(@as(f32, 2.2)), result[1], epsilon));
|
||||
try expect(math.approxEqAbs(f32, @cos(@as(f32, 3.3)), result[2], epsilon));
|
||||
try expect(math.approxEqAbs(f32, @cos(@as(f32, 4.4)), result[3], epsilon));
|
||||
}
|
||||
}
|
||||
|
||||
test "@exp" {
|
||||
comptime try testExp();
|
||||
try testExp();
|
||||
}
|
||||
|
||||
fn testExp() !void {
|
||||
// TODO test f128, and c_longdouble
|
||||
// https://github.com/ziglang/zig/issues/4026
|
||||
{
|
||||
var a: f16 = 0;
|
||||
try expect(@exp(a) == 1);
|
||||
}
|
||||
{
|
||||
var a: f32 = 0;
|
||||
try expect(@exp(a) == 1);
|
||||
}
|
||||
{
|
||||
var a: f64 = 0;
|
||||
try expect(@exp(a) == 1);
|
||||
}
|
||||
// {
|
||||
// var a: f80 = 0;
|
||||
// try expect(@exp(a) == 1);
|
||||
// }
|
||||
{
|
||||
var v: Vector(4, f32) = [_]f32{ 1.1, 2.2, 0.3, 0.4 };
|
||||
var result = @exp(v);
|
||||
try expect(math.approxEqAbs(f32, @exp(@as(f32, 1.1)), result[0], epsilon));
|
||||
try expect(math.approxEqAbs(f32, @exp(@as(f32, 2.2)), result[1], epsilon));
|
||||
try expect(math.approxEqAbs(f32, @exp(@as(f32, 0.3)), result[2], epsilon));
|
||||
try expect(math.approxEqAbs(f32, @exp(@as(f32, 0.4)), result[3], epsilon));
|
||||
}
|
||||
}
|
||||
|
||||
test "@exp2" {
|
||||
comptime try testExp2();
|
||||
try testExp2();
|
||||
}
|
||||
|
||||
fn testExp2() !void {
|
||||
// TODO test f128, and c_longdouble
|
||||
// https://github.com/ziglang/zig/issues/4026
|
||||
{
|
||||
var a: f16 = 2;
|
||||
try expect(@exp2(a) == 4);
|
||||
}
|
||||
{
|
||||
var a: f32 = 2;
|
||||
try expect(@exp2(a) == 4);
|
||||
}
|
||||
{
|
||||
var a: f64 = 2;
|
||||
try expect(@exp2(a) == 4);
|
||||
}
|
||||
// {
|
||||
// var a: f80 = 2;
|
||||
// try expect(@exp2(a) == 4);
|
||||
// }
|
||||
{
|
||||
var v: Vector(4, f32) = [_]f32{ 1.1, 2.2, 0.3, 0.4 };
|
||||
var result = @exp2(v);
|
||||
try expect(math.approxEqAbs(f32, @exp2(@as(f32, 1.1)), result[0], epsilon));
|
||||
try expect(math.approxEqAbs(f32, @exp2(@as(f32, 2.2)), result[1], epsilon));
|
||||
try expect(math.approxEqAbs(f32, @exp2(@as(f32, 0.3)), result[2], epsilon));
|
||||
try expect(math.approxEqAbs(f32, @exp2(@as(f32, 0.4)), result[3], epsilon));
|
||||
}
|
||||
}
|
||||
|
||||
test "@log" {
|
||||
// Old musl (and glibc?), and our current math.ln implementation do not return 1
|
||||
// so also accept those values.
|
||||
comptime try testLog();
|
||||
try testLog();
|
||||
}
|
||||
|
||||
fn testLog() !void {
|
||||
// TODO test f128, and c_longdouble
|
||||
// https://github.com/ziglang/zig/issues/4026
|
||||
{
|
||||
var a: f16 = e;
|
||||
try expect(math.approxEqAbs(f16, @log(a), 1, epsilon));
|
||||
}
|
||||
{
|
||||
var a: f32 = e;
|
||||
try expect(@log(a) == 1 or @log(a) == @bitCast(f32, @as(u32, 0x3f7fffff)));
|
||||
}
|
||||
{
|
||||
var a: f64 = e;
|
||||
try expect(@log(a) == 1 or @log(a) == @bitCast(f64, @as(u64, 0x3ff0000000000000)));
|
||||
}
|
||||
// {
|
||||
// var a: f80 = e;
|
||||
// try expect(@log(a) == 1);
|
||||
// }
|
||||
{
|
||||
var v: Vector(4, f32) = [_]f32{ 1.1, 2.2, 0.3, 0.4 };
|
||||
var result = @log(v);
|
||||
try expect(math.approxEqAbs(f32, @log(@as(f32, 1.1)), result[0], epsilon));
|
||||
try expect(math.approxEqAbs(f32, @log(@as(f32, 2.2)), result[1], epsilon));
|
||||
try expect(math.approxEqAbs(f32, @log(@as(f32, 0.3)), result[2], epsilon));
|
||||
try expect(math.approxEqAbs(f32, @log(@as(f32, 0.4)), result[3], epsilon));
|
||||
}
|
||||
}
|
||||
|
||||
test "@log2" {
|
||||
comptime try testLog2();
|
||||
try testLog2();
|
||||
}
|
||||
|
||||
fn testLog2() !void {
|
||||
// TODO test f128, and c_longdouble
|
||||
// https://github.com/ziglang/zig/issues/4026
|
||||
{
|
||||
var a: f16 = 4;
|
||||
try expect(@log2(a) == 2);
|
||||
}
|
||||
{
|
||||
var a: f32 = 4;
|
||||
try expect(@log2(a) == 2);
|
||||
}
|
||||
{
|
||||
var a: f64 = 4;
|
||||
try expect(@log2(a) == 2);
|
||||
}
|
||||
// {
|
||||
// var a: f80 = 4;
|
||||
// try expect(@log2(a) == 2);
|
||||
// }
|
||||
{
|
||||
var v: Vector(4, f32) = [_]f32{ 1.1, 2.2, 0.3, 0.4 };
|
||||
var result = @log2(v);
|
||||
try expect(math.approxEqAbs(f32, @log2(@as(f32, 1.1)), result[0], epsilon));
|
||||
try expect(math.approxEqAbs(f32, @log2(@as(f32, 2.2)), result[1], epsilon));
|
||||
try expect(math.approxEqAbs(f32, @log2(@as(f32, 0.3)), result[2], epsilon));
|
||||
try expect(math.approxEqAbs(f32, @log2(@as(f32, 0.4)), result[3], epsilon));
|
||||
}
|
||||
}
|
||||
|
||||
test "@log10" {
|
||||
comptime try testLog10();
|
||||
try testLog10();
|
||||
}
|
||||
|
||||
fn testLog10() !void {
|
||||
// TODO test f128, and c_longdouble
|
||||
// https://github.com/ziglang/zig/issues/4026
|
||||
{
|
||||
var a: f16 = 100;
|
||||
try expect(@log10(a) == 2);
|
||||
}
|
||||
{
|
||||
var a: f32 = 100;
|
||||
try expect(@log10(a) == 2);
|
||||
}
|
||||
{
|
||||
var a: f64 = 1000;
|
||||
try expect(@log10(a) == 3);
|
||||
}
|
||||
// {
|
||||
// var a: f80 = 1000;
|
||||
// try expect(@log10(a) == 3);
|
||||
// }
|
||||
{
|
||||
var v: Vector(4, f32) = [_]f32{ 1.1, 2.2, 0.3, 0.4 };
|
||||
var result = @log10(v);
|
||||
try expect(math.approxEqAbs(f32, @log10(@as(f32, 1.1)), result[0], epsilon));
|
||||
try expect(math.approxEqAbs(f32, @log10(@as(f32, 2.2)), result[1], epsilon));
|
||||
try expect(math.approxEqAbs(f32, @log10(@as(f32, 0.3)), result[2], epsilon));
|
||||
try expect(math.approxEqAbs(f32, @log10(@as(f32, 0.4)), result[3], epsilon));
|
||||
}
|
||||
}
|
||||
|
||||
test "@fabs" {
|
||||
comptime try testFabs();
|
||||
try testFabs();
|
||||
}
|
||||
|
||||
fn testFabs() !void {
|
||||
// TODO test f128, and c_longdouble
|
||||
// https://github.com/ziglang/zig/issues/4026
|
||||
{
|
||||
var a: f16 = -2.5;
|
||||
var b: f16 = 2.5;
|
||||
try expect(@fabs(a) == 2.5);
|
||||
try expect(@fabs(b) == 2.5);
|
||||
}
|
||||
{
|
||||
var a: f32 = -2.5;
|
||||
var b: f32 = 2.5;
|
||||
try expect(@fabs(a) == 2.5);
|
||||
try expect(@fabs(b) == 2.5);
|
||||
}
|
||||
{
|
||||
var a: f64 = -2.5;
|
||||
var b: f64 = 2.5;
|
||||
try expect(@fabs(a) == 2.5);
|
||||
try expect(@fabs(b) == 2.5);
|
||||
}
|
||||
// {
|
||||
// var a: f80 = -2.5;
|
||||
// var b: f80 = 2.5;
|
||||
// try expect(@fabs(a) == 2.5);
|
||||
// try expect(@fabs(b) == 2.5);
|
||||
// }
|
||||
{
|
||||
var v: Vector(4, f32) = [_]f32{ 1.1, -2.2, 0.3, -0.4 };
|
||||
var result = @fabs(v);
|
||||
try expect(math.approxEqAbs(f32, @fabs(@as(f32, 1.1)), result[0], epsilon));
|
||||
try expect(math.approxEqAbs(f32, @fabs(@as(f32, -2.2)), result[1], epsilon));
|
||||
try expect(math.approxEqAbs(f32, @fabs(@as(f32, 0.3)), result[2], epsilon));
|
||||
try expect(math.approxEqAbs(f32, @fabs(@as(f32, -0.4)), result[3], epsilon));
|
||||
}
|
||||
}
|
||||
|
||||
test "@floor" {
|
||||
comptime try testFloor();
|
||||
try testFloor();
|
||||
}
|
||||
|
||||
fn testFloor() !void {
|
||||
// TODO test f128, and c_longdouble
|
||||
// https://github.com/ziglang/zig/issues/4026
|
||||
{
|
||||
var a: f16 = 2.1;
|
||||
try expect(@floor(a) == 2);
|
||||
}
|
||||
{
|
||||
var a: f32 = 2.1;
|
||||
try expect(@floor(a) == 2);
|
||||
}
|
||||
{
|
||||
var a: f64 = 3.5;
|
||||
try expect(@floor(a) == 3);
|
||||
}
|
||||
// {
|
||||
// var a: f80 = 3.5;
|
||||
// try expect(@floor(a) == 3);
|
||||
// }
|
||||
{
|
||||
var v: Vector(4, f32) = [_]f32{ 1.1, -2.2, 0.3, -0.4 };
|
||||
var result = @floor(v);
|
||||
try expect(math.approxEqAbs(f32, @floor(@as(f32, 1.1)), result[0], epsilon));
|
||||
try expect(math.approxEqAbs(f32, @floor(@as(f32, -2.2)), result[1], epsilon));
|
||||
try expect(math.approxEqAbs(f32, @floor(@as(f32, 0.3)), result[2], epsilon));
|
||||
try expect(math.approxEqAbs(f32, @floor(@as(f32, -0.4)), result[3], epsilon));
|
||||
}
|
||||
}
|
||||
|
||||
test "@ceil" {
|
||||
comptime try testCeil();
|
||||
try testCeil();
|
||||
}
|
||||
|
||||
fn testCeil() !void {
|
||||
// TODO test f128, and c_longdouble
|
||||
// https://github.com/ziglang/zig/issues/4026
|
||||
{
|
||||
var a: f16 = 2.1;
|
||||
try expect(@ceil(a) == 3);
|
||||
}
|
||||
{
|
||||
var a: f32 = 2.1;
|
||||
try expect(@ceil(a) == 3);
|
||||
}
|
||||
{
|
||||
var a: f64 = 3.5;
|
||||
try expect(@ceil(a) == 4);
|
||||
}
|
||||
// {
|
||||
// var a: f80 = 3.5;
|
||||
// try expect(@ceil(a) == 4);
|
||||
// }
|
||||
{
|
||||
var v: Vector(4, f32) = [_]f32{ 1.1, -2.2, 0.3, -0.4 };
|
||||
var result = @ceil(v);
|
||||
try expect(math.approxEqAbs(f32, @ceil(@as(f32, 1.1)), result[0], epsilon));
|
||||
try expect(math.approxEqAbs(f32, @ceil(@as(f32, -2.2)), result[1], epsilon));
|
||||
try expect(math.approxEqAbs(f32, @ceil(@as(f32, 0.3)), result[2], epsilon));
|
||||
try expect(math.approxEqAbs(f32, @ceil(@as(f32, -0.4)), result[3], epsilon));
|
||||
}
|
||||
}
|
||||
|
||||
test "@trunc" {
|
||||
comptime try testTrunc();
|
||||
try testTrunc();
|
||||
}
|
||||
|
||||
fn testTrunc() !void {
|
||||
// TODO test f128, and c_longdouble
|
||||
// https://github.com/ziglang/zig/issues/4026
|
||||
{
|
||||
var a: f16 = 2.1;
|
||||
try expect(@trunc(a) == 2);
|
||||
}
|
||||
{
|
||||
var a: f32 = 2.1;
|
||||
try expect(@trunc(a) == 2);
|
||||
}
|
||||
{
|
||||
var a: f64 = -3.5;
|
||||
try expect(@trunc(a) == -3);
|
||||
}
|
||||
// {
|
||||
// var a: f80 = -3.5;
|
||||
// try expect(@trunc(a) == -3);
|
||||
// }
|
||||
{
|
||||
var v: Vector(4, f32) = [_]f32{ 1.1, -2.2, 0.3, -0.4 };
|
||||
var result = @trunc(v);
|
||||
try expect(math.approxEqAbs(f32, @trunc(@as(f32, 1.1)), result[0], epsilon));
|
||||
try expect(math.approxEqAbs(f32, @trunc(@as(f32, -2.2)), result[1], epsilon));
|
||||
try expect(math.approxEqAbs(f32, @trunc(@as(f32, 0.3)), result[2], epsilon));
|
||||
try expect(math.approxEqAbs(f32, @trunc(@as(f32, -0.4)), result[3], epsilon));
|
||||
}
|
||||
}
|
||||
|
||||
test "floating point comparisons" {
|
||||
if (has_f80_rt) try testFloatComparisons();
|
||||
comptime try testFloatComparisons();
|
||||
}
|
||||
|
||||
fn testFloatComparisons() !void {
|
||||
inline for ([_]type{ f16, f32, f64, f80, f128 }) |ty| {
|
||||
// No decimal part
|
||||
{
|
||||
const x: ty = 1.0;
|
||||
try expect(x == 1);
|
||||
try expect(x != 0);
|
||||
try expect(x > 0);
|
||||
try expect(x < 2);
|
||||
try expect(x >= 1);
|
||||
try expect(x <= 1);
|
||||
}
|
||||
// Non-zero decimal part
|
||||
{
|
||||
const x: ty = 1.5;
|
||||
try expect(x != 1);
|
||||
try expect(x != 2);
|
||||
try expect(x > 1);
|
||||
try expect(x < 2);
|
||||
try expect(x >= 1);
|
||||
try expect(x <= 2);
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user