diff --git a/src/Air.zig b/src/Air.zig index a044dd6294..623da26255 100644 --- a/src/Air.zig +++ b/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, diff --git a/src/Liveness.zig b/src/Liveness.zig index bed7de1507..12ba63fc00 100644 --- a/src/Liveness.zig +++ b/src/Liveness.zig @@ -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 }); diff --git a/src/Sema.zig b/src/Sema.zig index 4ff535d86e..4d38c6b7f7 100644 --- a/src/Sema.zig +++ b/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), diff --git a/src/arch/aarch64/CodeGen.zig b/src/arch/aarch64/CodeGen.zig index d0413af02f..42f2c66df1 100644 --- a/src/arch/aarch64/CodeGen.zig +++ b/src/arch/aarch64/CodeGen.zig @@ -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), diff --git a/src/arch/arm/CodeGen.zig b/src/arch/arm/CodeGen.zig index 2116717cd1..711e2a96f0 100644 --- a/src/arch/arm/CodeGen.zig +++ b/src/arch/arm/CodeGen.zig @@ -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), diff --git a/src/arch/riscv64/CodeGen.zig b/src/arch/riscv64/CodeGen.zig index ce5dc39bf8..09ca92f229 100644 --- a/src/arch/riscv64/CodeGen.zig +++ b/src/arch/riscv64/CodeGen.zig @@ -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), diff --git a/src/arch/wasm/CodeGen.zig b/src/arch/wasm/CodeGen.zig index 5186f0231b..b0c24be03b 100644 --- a/src/arch/wasm/CodeGen.zig +++ b/src/arch/wasm/CodeGen.zig @@ -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, diff --git a/src/arch/x86_64/CodeGen.zig b/src/arch/x86_64/CodeGen.zig index de8f907dea..d78245b094 100644 --- a/src/arch/x86_64/CodeGen.zig +++ b/src/arch/x86_64/CodeGen.zig @@ -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), diff --git a/src/codegen/c.zig b/src/codegen/c.zig index fc3848df21..5d7bdcee55 100644 --- a/src/codegen/c.zig +++ b/src/codegen/c.zig @@ -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", diff --git a/src/codegen/llvm.zig b/src/codegen/llvm.zig index 5a2c21eece..9c9bf0d0f2 100644 --- a/src/codegen/llvm.zig +++ b/src/codegen/llvm.zig @@ -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, ""); diff --git a/src/print_air.zig b/src/print_air.zig index 341e736b91..bcadf31e74 100644 --- a/src/print_air.zig +++ b/src/print_air.zig @@ -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, diff --git a/src/value.zig b/src/value.zig index 9e1f4c0ed6..33a75e08bb 100644 --- a/src/value.zig +++ b/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, diff --git a/test/behavior.zig b/test/behavior.zig index c177dd8634..b2ffbabde2 100644 --- a/test/behavior.zig +++ b/test/behavior.zig @@ -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"); diff --git a/test/behavior/floatop.zig b/test/behavior/floatop.zig index 7807c690f6..ed632c26c5 100644 --- a/test/behavior/floatop.zig +++ b/test/behavior/floatop.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)); + } +} diff --git a/test/behavior/floatop_stage1.zig b/test/behavior/floatop_stage1.zig deleted file mode 100644 index cd11f41b40..0000000000 --- a/test/behavior/floatop_stage1.zig +++ /dev/null @@ -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); - } - } -}