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:
John Schmidt 2022-02-04 20:21:15 +01:00 committed by Andrew Kelley
parent 44b5fdf326
commit 7f0cf395aa
15 changed files with 917 additions and 494 deletions

View File

@ -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,

View File

@ -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 });

View File

@ -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),

View File

@ -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),

View File

@ -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),

View File

@ -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),

View File

@ -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,

View File

@ -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),

View File

@ -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",

View File

@ -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, &params, params.len, .C, .Auto, "");

View File

@ -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,

View File

@ -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,

View File

@ -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");

View File

@ -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));
}
}

View File

@ -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);
}
}
}