authorgravatar for john.schmidt.h@gmail.comJohn Schmidt <john.schmidt.h@gmail.com> 2022-02-04 20:21:15+01:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-02-09 20:29:41-05:00
log7f0cf395aa74eb5ea250bd28f7525b3036790a6a
treee2faf4e4a19836331d3e47180438fab4db4fb178
parent44b5fdf3266f11607313bc9990a876b5a7f9e174

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.

15 files changed, 917 insertions(+), 494 deletions(-)

src/Air.zig+51-2
......@@ -237,9 +237,45 @@ pub const Inst = struct {
237237 /// Uses the `ty_op` field.
238238 popcount,
239239
240 /// Computes the square root of a floating point number.
240 /// Square root of a floating point number.
241241 /// Uses the `un_op` field.
242242 sqrt,
243 /// Sine a floating point number.
244 /// Uses the `un_op` field.
245 sin,
246 /// Cosine a floating point number.
247 /// Uses the `un_op` field.
248 cos,
249 /// Base e exponential of a floating point number.
250 /// Uses the `un_op` field.
251 exp,
252 /// Base 2 exponential of a floating point number.
253 /// Uses the `un_op` field.
254 exp2,
255 /// Natural (base e) logarithm of a floating point number.
256 /// Uses the `un_op` field.
257 log,
258 /// Base 2 logarithm of a floating point number.
259 /// Uses the `un_op` field.
260 log2,
261 /// Base 10 logarithm of a floating point number.
262 /// Uses the `un_op` field.
263 log10,
264 /// Aboslute value of a floating point number.
265 /// Uses the `un_op` field.
266 fabs,
267 /// Floor: rounds a floating pointer number down to the nearest integer.
268 /// Uses the `un_op` field.
269 floor,
270 /// Ceiling: rounds a floating pointer number up to the nearest integer.
271 /// Uses the `un_op` field.
272 ceil,
273 /// Rounds a floating pointer number to the nearest integer.
274 /// Uses the `un_op` field.
275 round,
276 /// Rounds a floating pointer number to the nearest integer towards zero.
277 /// Uses the `un_op` field.
278 trunc_float,
243279
244280 /// `<`. Result type is always bool.
245281 /// Uses the `bin_op` field.
......@@ -754,7 +790,20 @@ pub fn typeOfIndex(air: Air, inst: Air.Inst.Index) Type {
754790 .max,
755791 => return air.typeOf(datas[inst].bin_op.lhs),
756792
757 .sqrt => return air.typeOf(datas[inst].un_op),
793 .sqrt,
794 .sin,
795 .cos,
796 .exp,
797 .exp2,
798 .log,
799 .log2,
800 .log10,
801 .fabs,
802 .floor,
803 .ceil,
804 .round,
805 .trunc_float,
806 => return air.typeOf(datas[inst].un_op),
758807
759808 .cmp_lt,
760809 .cmp_lte,
src/Liveness.zig+12
......@@ -339,6 +339,18 @@ fn analyzeInst(
339339 .tag_name,
340340 .error_name,
341341 .sqrt,
342 .sin,
343 .cos,
344 .exp,
345 .exp2,
346 .log,
347 .log2,
348 .log10,
349 .fabs,
350 .floor,
351 .ceil,
352 .round,
353 .trunc_float,
342354 => {
343355 const operand = inst_datas[inst].un_op;
344356 return trackOperands(a, new_set, inst, main_tomb, .{ operand, .none, .none });
src/Sema.zig+12-12
......@@ -747,18 +747,18 @@ fn analyzeBodyInner(
747747 .ctz => try sema.zirClzCtz(block, inst, .ctz, Value.ctz),
748748
749749 .sqrt => try sema.zirUnaryMath(block, inst, .sqrt, Value.sqrt),
750 .sin => @panic("TODO"),
751 .cos => @panic("TODO"),
752 .exp => @panic("TODO"),
753 .exp2 => @panic("TODO"),
754 .log => @panic("TODO"),
755 .log2 => @panic("TODO"),
756 .log10 => @panic("TODO"),
757 .fabs => @panic("TODO"),
758 .floor => @panic("TODO"),
759 .ceil => @panic("TODO"),
760 .trunc => @panic("TODO"),
761 .round => @panic("TODO"),
750 .sin => try sema.zirUnaryMath(block, inst, .sin, Value.sin),
751 .cos => try sema.zirUnaryMath(block, inst, .cos, Value.cos),
752 .exp => try sema.zirUnaryMath(block, inst, .exp, Value.exp),
753 .exp2 => try sema.zirUnaryMath(block, inst, .exp2, Value.exp2),
754 .log => try sema.zirUnaryMath(block, inst, .log, Value.log),
755 .log2 => try sema.zirUnaryMath(block, inst, .log2, Value.log2),
756 .log10 => try sema.zirUnaryMath(block, inst, .log10, Value.log10),
757 .fabs => try sema.zirUnaryMath(block, inst, .fabs, Value.fabs),
758 .floor => try sema.zirUnaryMath(block, inst, .floor, Value.floor),
759 .ceil => try sema.zirUnaryMath(block, inst, .ceil, Value.ceil),
760 .round => try sema.zirUnaryMath(block, inst, .round, Value.round),
761 .trunc => try sema.zirUnaryMath(block, inst, .trunc_float, Value.trunc),
762762
763763 .error_set_decl => try sema.zirErrorSetDecl(block, inst, .parent),
764764 .error_set_decl_anon => try sema.zirErrorSetDecl(block, inst, .anon),
src/arch/aarch64/CodeGen.zig+14-1
......@@ -528,7 +528,20 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
528528 .max => try self.airMax(inst),
529529 .slice => try self.airSlice(inst),
530530
531 .sqrt => try self.airUnaryMath(inst),
531 .sqrt,
532 .sin,
533 .cos,
534 .exp,
535 .exp2,
536 .log,
537 .log2,
538 .log10,
539 .fabs,
540 .floor,
541 .ceil,
542 .round,
543 .trunc_float
544 => try self.airUnaryMath(inst),
532545
533546 .add_with_overflow => try self.airAddWithOverflow(inst),
534547 .sub_with_overflow => try self.airSubWithOverflow(inst),
src/arch/arm/CodeGen.zig+14-1
......@@ -520,7 +520,20 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
520520 .max => try self.airMax(inst),
521521 .slice => try self.airSlice(inst),
522522
523 .sqrt => try self.airUnaryMath(inst),
523 .sqrt,
524 .sin,
525 .cos,
526 .exp,
527 .exp2,
528 .log,
529 .log2,
530 .log10,
531 .fabs,
532 .floor,
533 .ceil,
534 .round,
535 .trunc_float,
536 => try self.airUnaryMath(inst),
524537
525538 .add_with_overflow => try self.airAddWithOverflow(inst),
526539 .sub_with_overflow => try self.airSubWithOverflow(inst),
src/arch/riscv64/CodeGen.zig+14-1
......@@ -507,7 +507,20 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
507507 .max => try self.airMax(inst),
508508 .slice => try self.airSlice(inst),
509509
510 .sqrt => try self.airUnaryMath(inst),
510 .sqrt,
511 .sin,
512 .cos,
513 .exp,
514 .exp2,
515 .log,
516 .log2,
517 .log10,
518 .fabs,
519 .floor,
520 .ceil,
521 .round,
522 .trunc_float,
523 => try self.airUnaryMath(inst),
511524
512525 .add_with_overflow => try self.airAddWithOverflow(inst),
513526 .sub_with_overflow => try self.airSubWithOverflow(inst),
src/arch/wasm/CodeGen.zig+12
......@@ -1679,6 +1679,18 @@ fn genInst(self: *Self, inst: Air.Inst.Index) !WValue {
16791679 .unwrap_errunion_err_ptr,
16801680
16811681 .sqrt,
1682 .sin,
1683 .cos,
1684 .exp,
1685 .exp2,
1686 .log,
1687 .log2,
1688 .log10,
1689 .fabs,
1690 .floor,
1691 .ceil,
1692 .round,
1693 .trunc_float,
16821694
16831695 .ptr_slice_len_ptr,
16841696 .ptr_slice_ptr_ptr,
src/arch/x86_64/CodeGen.zig+14-1
......@@ -599,7 +599,20 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
599599 .max => try self.airMax(inst),
600600 .slice => try self.airSlice(inst),
601601
602 .sqrt => try self.airUnaryMath(inst),
602 .sqrt,
603 .sin,
604 .cos,
605 .exp,
606 .exp2,
607 .log,
608 .log2,
609 .log10,
610 .fabs,
611 .floor,
612 .ceil,
613 .round,
614 .trunc_float,
615 => try self.airUnaryMath(inst),
603616
604617 .add_with_overflow => try self.airAddWithOverflow(inst),
605618 .sub_with_overflow => try self.airSubWithOverflow(inst),
src/codegen/c.zig+14-7
......@@ -1446,7 +1446,20 @@ fn genBody(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail, OutO
14461446 .mul_sat => try airSatOp(f, inst, "muls_"),
14471447 .shl_sat => try airSatOp(f, inst, "shls_"),
14481448
1449 .sqrt => try airSqrt(f, inst),
1449 .sqrt,
1450 .sin,
1451 .cos,
1452 .exp,
1453 .exp2,
1454 .log,
1455 .log2,
1456 .log10,
1457 .fabs,
1458 .floor,
1459 .ceil,
1460 .round,
1461 .trunc_float,
1462 => |tag| return f.fail("TODO: C backend: implement unary op for tag '{s}'", .{@tagName(tag)}),
14501463
14511464 .add_with_overflow => try airAddWithOverflow(f, inst),
14521465 .sub_with_overflow => try airSubWithOverflow(f, inst),
......@@ -3395,12 +3408,6 @@ fn airPrefetch(f: *Function, inst: Air.Inst.Index) !CValue {
33953408 return CValue.none;
33963409}
33973410
3398fn airSqrt(f: *Function, inst: Air.Inst.Index) !CValue {
3399 _ = f;
3400 _ = inst;
3401 return f.fail("TODO: C backend: implement sqrt", .{});
3402}
3403
34043411fn toMemoryOrder(order: std.builtin.AtomicOrder) [:0]const u8 {
34053412 return switch (order) {
34063413 .Unordered => "memory_order_relaxed",
src/codegen/llvm.zig+15-3
......@@ -2050,7 +2050,19 @@ pub const FuncGen = struct {
20502050 .shr => try self.airShr(inst, false),
20512051 .shr_exact => try self.airShr(inst, true),
20522052
2053 .sqrt => try self.airSqrt(inst),
2053 .sqrt => try self.airUnaryOp(inst, "llvm.sqrt"),
2054 .sin => try self.airUnaryOp(inst, "llvm.sin"),
2055 .cos => try self.airUnaryOp(inst, "llvm.cos"),
2056 .exp => try self.airUnaryOp(inst, "llvm.exp"),
2057 .exp2 => try self.airUnaryOp(inst, "llvm.exp2"),
2058 .log => try self.airUnaryOp(inst, "llvm.log"),
2059 .log2 => try self.airUnaryOp(inst, "llvm.log2"),
2060 .log10 => try self.airUnaryOp(inst, "llvm.log10"),
2061 .fabs => try self.airUnaryOp(inst, "llvm.fabs"),
2062 .floor => try self.airUnaryOp(inst, "llvm.floor"),
2063 .ceil => try self.airUnaryOp(inst, "llvm.ceil"),
2064 .round => try self.airUnaryOp(inst, "llvm.round"),
2065 .trunc_float => try self.airUnaryOp(inst, "llvm.trunc"),
20542066
20552067 .cmp_eq => try self.airCmp(inst, .eq),
20562068 .cmp_gt => try self.airCmp(inst, .gt),
......@@ -4213,7 +4225,7 @@ pub const FuncGen = struct {
42134225 }
42144226 }
42154227
4216 fn airSqrt(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value {
4228 fn airUnaryOp(self: *FuncGen, inst: Air.Inst.Index, llvm_fn_name: []const u8) !?*const llvm.Value {
42174229 if (self.liveness.isUnused(inst)) return null;
42184230
42194231 const un_op = self.air.instructions.items(.data)[inst].un_op;
......@@ -4221,7 +4233,7 @@ pub const FuncGen = struct {
42214233 const operand_ty = self.air.typeOf(un_op);
42224234
42234235 const operand_llvm_ty = try self.dg.llvmType(operand_ty);
4224 const fn_val = self.getIntrinsic("llvm.sqrt", &.{operand_llvm_ty});
4236 const fn_val = self.getIntrinsic(llvm_fn_name, &.{operand_llvm_ty});
42254237 const params = [_]*const llvm.Value{operand};
42264238
42274239 return self.builder.buildCall(fn_val, &params, params.len, .C, .Auto, "");
src/print_air.zig+12
......@@ -159,6 +159,18 @@ const Writer = struct {
159159 .tag_name,
160160 .error_name,
161161 .sqrt,
162 .sin,
163 .cos,
164 .exp,
165 .exp2,
166 .log,
167 .log2,
168 .log10,
169 .fabs,
170 .floor,
171 .ceil,
172 .round,
173 .trunc_float,
162174 => try w.writeUnOp(s, inst),
163175
164176 .breakpoint,
src/value.zig+384
......@@ -3308,6 +3308,390 @@ pub const Value = extern union {
33083308 }
33093309 }
33103310
3311 pub fn sin(val: Value, float_type: Type, arena: Allocator, target: Target) Allocator.Error!Value {
3312 switch (float_type.floatBits(target)) {
3313 16 => {
3314 const f = val.toFloat(f16);
3315 return Value.Tag.float_16.create(arena, @sin(f));
3316 },
3317 32 => {
3318 const f = val.toFloat(f32);
3319 return Value.Tag.float_32.create(arena, @sin(f));
3320 },
3321 64 => {
3322 const f = val.toFloat(f64);
3323 return Value.Tag.float_64.create(arena, @sin(f));
3324 },
3325 80 => {
3326 if (true) {
3327 @panic("TODO implement compiler_rt sin for f80");
3328 }
3329 const f = val.toFloat(f80);
3330 return Value.Tag.float_80.create(arena, @sin(f));
3331 },
3332 128 => {
3333 if (true) {
3334 @panic("TODO implement compiler_rt sin for f128");
3335 }
3336 const f = val.toFloat(f128);
3337 return Value.Tag.float_128.create(arena, @sin(f));
3338 },
3339 else => unreachable,
3340 }
3341 }
3342
3343 pub fn cos(val: Value, float_type: Type, arena: Allocator, target: Target) Allocator.Error!Value {
3344 switch (float_type.floatBits(target)) {
3345 16 => {
3346 const f = val.toFloat(f16);
3347 return Value.Tag.float_16.create(arena, @cos(f));
3348 },
3349 32 => {
3350 const f = val.toFloat(f32);
3351 return Value.Tag.float_32.create(arena, @cos(f));
3352 },
3353 64 => {
3354 const f = val.toFloat(f64);
3355 return Value.Tag.float_64.create(arena, @cos(f));
3356 },
3357 80 => {
3358 if (true) {
3359 @panic("TODO implement compiler_rt cos for f80");
3360 }
3361 const f = val.toFloat(f80);
3362 return Value.Tag.float_80.create(arena, @cos(f));
3363 },
3364 128 => {
3365 if (true) {
3366 @panic("TODO implement compiler_rt cos for f128");
3367 }
3368 const f = val.toFloat(f128);
3369 return Value.Tag.float_128.create(arena, @cos(f));
3370 },
3371 else => unreachable,
3372 }
3373 }
3374
3375 pub fn exp(val: Value, float_type: Type, arena: Allocator, target: Target) Allocator.Error!Value {
3376 switch (float_type.floatBits(target)) {
3377 16 => {
3378 const f = val.toFloat(f16);
3379 return Value.Tag.float_16.create(arena, @exp(f));
3380 },
3381 32 => {
3382 const f = val.toFloat(f32);
3383 return Value.Tag.float_32.create(arena, @exp(f));
3384 },
3385 64 => {
3386 const f = val.toFloat(f64);
3387 return Value.Tag.float_64.create(arena, @exp(f));
3388 },
3389 80 => {
3390 if (true) {
3391 @panic("TODO implement compiler_rt exp for f80");
3392 }
3393 const f = val.toFloat(f80);
3394 return Value.Tag.float_80.create(arena, @exp(f));
3395 },
3396 128 => {
3397 if (true) {
3398 @panic("TODO implement compiler_rt exp for f128");
3399 }
3400 const f = val.toFloat(f128);
3401 return Value.Tag.float_128.create(arena, @exp(f));
3402 },
3403 else => unreachable,
3404 }
3405 }
3406
3407 pub fn exp2(val: Value, float_type: Type, arena: Allocator, target: Target) Allocator.Error!Value {
3408 switch (float_type.floatBits(target)) {
3409 16 => {
3410 const f = val.toFloat(f16);
3411 return Value.Tag.float_16.create(arena, @exp2(f));
3412 },
3413 32 => {
3414 const f = val.toFloat(f32);
3415 return Value.Tag.float_32.create(arena, @exp2(f));
3416 },
3417 64 => {
3418 const f = val.toFloat(f64);
3419 return Value.Tag.float_64.create(arena, @exp2(f));
3420 },
3421 80 => {
3422 if (true) {
3423 @panic("TODO implement compiler_rt exp2 for f80");
3424 }
3425 const f = val.toFloat(f80);
3426 return Value.Tag.float_80.create(arena, @exp2(f));
3427 },
3428 128 => {
3429 if (true) {
3430 @panic("TODO implement compiler_rt exp2 for f128");
3431 }
3432 const f = val.toFloat(f128);
3433 return Value.Tag.float_128.create(arena, @exp2(f));
3434 },
3435 else => unreachable,
3436 }
3437 }
3438
3439 pub fn log(val: Value, float_type: Type, arena: Allocator, target: Target) Allocator.Error!Value {
3440 switch (float_type.floatBits(target)) {
3441 16 => {
3442 const f = val.toFloat(f16);
3443 return Value.Tag.float_16.create(arena, @log(f));
3444 },
3445 32 => {
3446 const f = val.toFloat(f32);
3447 return Value.Tag.float_32.create(arena, @log(f));
3448 },
3449 64 => {
3450 const f = val.toFloat(f64);
3451 return Value.Tag.float_64.create(arena, @log(f));
3452 },
3453 80 => {
3454 if (true) {
3455 @panic("TODO implement compiler_rt log for f80");
3456 }
3457 const f = val.toFloat(f80);
3458 return Value.Tag.float_80.create(arena, @log(f));
3459 },
3460 128 => {
3461 if (true) {
3462 @panic("TODO implement compiler_rt log for f128");
3463 }
3464 const f = val.toFloat(f128);
3465 return Value.Tag.float_128.create(arena, @log(f));
3466 },
3467 else => unreachable,
3468 }
3469 }
3470
3471 pub fn log2(val: Value, float_type: Type, arena: Allocator, target: Target) Allocator.Error!Value {
3472 switch (float_type.floatBits(target)) {
3473 16 => {
3474 const f = val.toFloat(f16);
3475 return Value.Tag.float_16.create(arena, @log2(f));
3476 },
3477 32 => {
3478 const f = val.toFloat(f32);
3479 return Value.Tag.float_32.create(arena, @log2(f));
3480 },
3481 64 => {
3482 const f = val.toFloat(f64);
3483 return Value.Tag.float_64.create(arena, @log2(f));
3484 },
3485 80 => {
3486 if (true) {
3487 @panic("TODO implement compiler_rt log2 for f80");
3488 }
3489 const f = val.toFloat(f80);
3490 return Value.Tag.float_80.create(arena, @log2(f));
3491 },
3492 128 => {
3493 if (true) {
3494 @panic("TODO implement compiler_rt log2 for f128");
3495 }
3496 const f = val.toFloat(f128);
3497 return Value.Tag.float_128.create(arena, @log2(f));
3498 },
3499 else => unreachable,
3500 }
3501 }
3502
3503 pub fn log10(val: Value, float_type: Type, arena: Allocator, target: Target) Allocator.Error!Value {
3504 switch (float_type.floatBits(target)) {
3505 16 => {
3506 const f = val.toFloat(f16);
3507 return Value.Tag.float_16.create(arena, @log10(f));
3508 },
3509 32 => {
3510 const f = val.toFloat(f32);
3511 return Value.Tag.float_32.create(arena, @log10(f));
3512 },
3513 64 => {
3514 const f = val.toFloat(f64);
3515 return Value.Tag.float_64.create(arena, @log10(f));
3516 },
3517 80 => {
3518 if (true) {
3519 @panic("TODO implement compiler_rt log10 for f80");
3520 }
3521 const f = val.toFloat(f80);
3522 return Value.Tag.float_80.create(arena, @log10(f));
3523 },
3524 128 => {
3525 if (true) {
3526 @panic("TODO implement compiler_rt log10 for f128");
3527 }
3528 const f = val.toFloat(f128);
3529 return Value.Tag.float_128.create(arena, @log10(f));
3530 },
3531 else => unreachable,
3532 }
3533 }
3534
3535 pub fn fabs(val: Value, float_type: Type, arena: Allocator, target: Target) Allocator.Error!Value {
3536 switch (float_type.floatBits(target)) {
3537 16 => {
3538 const f = val.toFloat(f16);
3539 return Value.Tag.float_16.create(arena, @fabs(f));
3540 },
3541 32 => {
3542 const f = val.toFloat(f32);
3543 return Value.Tag.float_32.create(arena, @fabs(f));
3544 },
3545 64 => {
3546 const f = val.toFloat(f64);
3547 return Value.Tag.float_64.create(arena, @fabs(f));
3548 },
3549 80 => {
3550 if (true) {
3551 @panic("TODO implement compiler_rt fabs for f80");
3552 }
3553 const f = val.toFloat(f80);
3554 return Value.Tag.float_80.create(arena, @fabs(f));
3555 },
3556 128 => {
3557 if (true) {
3558 @panic("TODO implement compiler_rt fabs for f128");
3559 }
3560 const f = val.toFloat(f128);
3561 return Value.Tag.float_128.create(arena, @fabs(f));
3562 },
3563 else => unreachable,
3564 }
3565 }
3566
3567 pub fn floor(val: Value, float_type: Type, arena: Allocator, target: Target) Allocator.Error!Value {
3568 switch (float_type.floatBits(target)) {
3569 16 => {
3570 const f = val.toFloat(f16);
3571 return Value.Tag.float_16.create(arena, @floor(f));
3572 },
3573 32 => {
3574 const f = val.toFloat(f32);
3575 return Value.Tag.float_32.create(arena, @floor(f));
3576 },
3577 64 => {
3578 const f = val.toFloat(f64);
3579 return Value.Tag.float_64.create(arena, @floor(f));
3580 },
3581 80 => {
3582 if (true) {
3583 @panic("TODO implement compiler_rt floor for f80");
3584 }
3585 const f = val.toFloat(f80);
3586 return Value.Tag.float_80.create(arena, @floor(f));
3587 },
3588 128 => {
3589 if (true) {
3590 @panic("TODO implement compiler_rt floor for f128");
3591 }
3592 const f = val.toFloat(f128);
3593 return Value.Tag.float_128.create(arena, @floor(f));
3594 },
3595 else => unreachable,
3596 }
3597 }
3598
3599 pub fn ceil(val: Value, float_type: Type, arena: Allocator, target: Target) Allocator.Error!Value {
3600 switch (float_type.floatBits(target)) {
3601 16 => {
3602 const f = val.toFloat(f16);
3603 return Value.Tag.float_16.create(arena, @ceil(f));
3604 },
3605 32 => {
3606 const f = val.toFloat(f32);
3607 return Value.Tag.float_32.create(arena, @ceil(f));
3608 },
3609 64 => {
3610 const f = val.toFloat(f64);
3611 return Value.Tag.float_64.create(arena, @ceil(f));
3612 },
3613 80 => {
3614 if (true) {
3615 @panic("TODO implement compiler_rt ceil for f80");
3616 }
3617 const f = val.toFloat(f80);
3618 return Value.Tag.float_80.create(arena, @ceil(f));
3619 },
3620 128 => {
3621 if (true) {
3622 @panic("TODO implement compiler_rt ceil for f128");
3623 }
3624 const f = val.toFloat(f128);
3625 return Value.Tag.float_128.create(arena, @ceil(f));
3626 },
3627 else => unreachable,
3628 }
3629 }
3630
3631 pub fn round(val: Value, float_type: Type, arena: Allocator, target: Target) Allocator.Error!Value {
3632 switch (float_type.floatBits(target)) {
3633 16 => {
3634 const f = val.toFloat(f16);
3635 return Value.Tag.float_16.create(arena, @round(f));
3636 },
3637 32 => {
3638 const f = val.toFloat(f32);
3639 return Value.Tag.float_32.create(arena, @round(f));
3640 },
3641 64 => {
3642 const f = val.toFloat(f64);
3643 return Value.Tag.float_64.create(arena, @round(f));
3644 },
3645 80 => {
3646 if (true) {
3647 @panic("TODO implement compiler_rt round for f80");
3648 }
3649 const f = val.toFloat(f80);
3650 return Value.Tag.float_80.create(arena, @round(f));
3651 },
3652 128 => {
3653 if (true) {
3654 @panic("TODO implement compiler_rt round for f128");
3655 }
3656 const f = val.toFloat(f128);
3657 return Value.Tag.float_128.create(arena, @round(f));
3658 },
3659 else => unreachable,
3660 }
3661 }
3662
3663 pub fn trunc(val: Value, float_type: Type, arena: Allocator, target: Target) Allocator.Error!Value {
3664 switch (float_type.floatBits(target)) {
3665 16 => {
3666 const f = val.toFloat(f16);
3667 return Value.Tag.float_16.create(arena, @trunc(f));
3668 },
3669 32 => {
3670 const f = val.toFloat(f32);
3671 return Value.Tag.float_32.create(arena, @trunc(f));
3672 },
3673 64 => {
3674 const f = val.toFloat(f64);
3675 return Value.Tag.float_64.create(arena, @trunc(f));
3676 },
3677 80 => {
3678 if (true) {
3679 @panic("TODO implement compiler_rt trunc for f80");
3680 }
3681 const f = val.toFloat(f80);
3682 return Value.Tag.float_80.create(arena, @trunc(f));
3683 },
3684 128 => {
3685 if (true) {
3686 @panic("TODO implement compiler_rt trunc for f128");
3687 }
3688 const f = val.toFloat(f128);
3689 return Value.Tag.float_128.create(arena, @trunc(f));
3690 },
3691 else => unreachable,
3692 }
3693 }
3694
33113695 /// This type is not copyable since it may contain pointers to its inner data.
33123696 pub const Payload = struct {
33133697 tag: Tag,
test/behavior.zig-1
......@@ -150,7 +150,6 @@ test {
150150 _ = @import("behavior/const_slice_child.zig");
151151 _ = @import("behavior/export_self_referential_type_info.zig");
152152 _ = @import("behavior/field_parent_ptr.zig");
153 _ = @import("behavior/floatop_stage1.zig");
154153 _ = @import("behavior/fn_delegation.zig");
155154 _ = @import("behavior/ir_block_deps.zig");
156155 _ = @import("behavior/misc.zig");
test/behavior/floatop.zig+349-13
......@@ -1,12 +1,22 @@
11const std = @import("std");
2const builtin = @import("builtin");
23const expect = std.testing.expect;
34const math = std.math;
45const pi = std.math.pi;
56const e = std.math.e;
67const Vector = std.meta.Vector;
8const has_f80_rt = @import("builtin").cpu.arch == .x86_64;
79
10const epsilon_16 = 0.001;
811const epsilon = 0.000001;
912
13fn epsForType(comptime T: type) T {
14 return switch (T) {
15 f16 => @as(f16, epsilon_16),
16 else => @as(T, epsilon),
17 };
18}
19
1020test "floating point comparisons" {
1121 try testFloatComparisons();
1222 comptime try testFloatComparisons();
......@@ -79,19 +89,37 @@ test "@sqrt" {
7989}
8090
8191fn testSqrt() !void {
82 {
83 var a: f16 = 4;
84 try expect(@sqrt(a) == 2);
85 }
86 {
87 var a: f32 = 9;
88 try expect(@sqrt(a) == 3);
89 var b: f32 = 1.1;
90 try expect(math.approxEqAbs(f32, @sqrt(b), 1.0488088481701516, epsilon));
91 }
92 {
93 var a: f64 = 25;
94 try expect(@sqrt(a) == 5);
92 try expect(@sqrt(@as(f16, 4)) == 2);
93 try expect(@sqrt(@as(f32, 9)) == 3);
94 try expect(@sqrt(@as(f64, 25)) == 5);
95 try expect(math.approxEqAbs(f32, @sqrt(@as(f32, 1.1)), 1.0488088481701516, epsilon));
96 try expect(math.approxEqAbs(f32, @sqrt(@as(f32, 2.0)), 1.4142135623730950, epsilon));
97
98 if (builtin.zig_backend == .stage1) {
99 if (has_f80_rt) {
100 var a: f80 = 25;
101 try expect(@sqrt(a) == 5);
102 }
103 {
104 const a: comptime_float = 25.0;
105 try expect(@sqrt(a) == 5.0);
106 }
107 // TODO test f128, and c_longdouble
108 // https://github.com/ziglang/zig/issues/4026
109 //{
110 // var a: f128 = 49;
111 //try expect(@sqrt(a) == 7);
112 //}
113
114 // TODO Implement Vector support for stage2
115 {
116 var v: Vector(4, f32) = [_]f32{ 1.1, 2.2, 3.3, 4.4 };
117 var result = @sqrt(v);
118 try expect(math.approxEqAbs(f32, @sqrt(@as(f32, 1.1)), result[0], epsilon));
119 try expect(math.approxEqAbs(f32, @sqrt(@as(f32, 2.2)), result[1], epsilon));
120 try expect(math.approxEqAbs(f32, @sqrt(@as(f32, 3.3)), result[2], epsilon));
121 try expect(math.approxEqAbs(f32, @sqrt(@as(f32, 4.4)), result[3], epsilon));
122 }
95123 }
96124}
97125
......@@ -114,3 +142,311 @@ test "more @sqrt f16 tests" {
114142 try expect(math.isNan(@sqrt(@as(f16, -1.0))));
115143 try expect(math.isNan(@sqrt(@as(f16, math.nan(f16)))));
116144}
145
146test "@sin" {
147 comptime try testSin();
148 try testSin();
149}
150
151fn testSin() !void {
152 // TODO: Implement Vector support for other backends
153 if (builtin.zig_backend == .stage1) {
154 var v: Vector(4, f32) = [_]f32{ 1.1, 2.2, 3.3, 4.4 };
155 var result = @sin(v);
156 try expect(math.approxEqAbs(f32, @sin(@as(f32, 1.1)), result[0], epsilon));
157 try expect(math.approxEqAbs(f32, @sin(@as(f32, 2.2)), result[1], epsilon));
158 try expect(math.approxEqAbs(f32, @sin(@as(f32, 3.3)), result[2], epsilon));
159 try expect(math.approxEqAbs(f32, @sin(@as(f32, 4.4)), result[3], epsilon));
160
161 // stage1 emits an incorrect compile error for `@as(ty, std.math.pi / 2)`
162 // so skip the rest of the tests.
163 return;
164 }
165
166 inline for ([_]type{ f16, f32, f64 }) |ty| {
167 const eps = epsForType(ty);
168 try expect(@sin(@as(ty, 0)) == 0);
169 try expect(math.approxEqAbs(ty, @sin(@as(ty, std.math.pi)), 0, eps));
170 try expect(math.approxEqAbs(ty, @sin(@as(ty, std.math.pi / 2)), 1, eps));
171 try expect(math.approxEqAbs(ty, @sin(@as(ty, std.math.pi / 4)), 0.7071067811865475, eps));
172 }
173}
174
175test "@cos" {
176 comptime try testCos();
177 try testCos();
178}
179
180fn testCos() !void {
181 // TODO: Implement Vector support for other backends
182 if (builtin.zig_backend == .stage1) {
183 var v: Vector(4, f32) = [_]f32{ 1.1, 2.2, 3.3, 4.4 };
184 var result = @cos(v);
185 try expect(math.approxEqAbs(f32, @cos(@as(f32, 1.1)), result[0], epsilon));
186 try expect(math.approxEqAbs(f32, @cos(@as(f32, 2.2)), result[1], epsilon));
187 try expect(math.approxEqAbs(f32, @cos(@as(f32, 3.3)), result[2], epsilon));
188 try expect(math.approxEqAbs(f32, @cos(@as(f32, 4.4)), result[3], epsilon));
189
190 // stage1 emits an incorrect compile error for `@as(ty, std.math.pi / 2)`
191 // so skip the rest of the tests.
192 return;
193 }
194
195 inline for ([_]type{ f16, f32, f64 }) |ty| {
196 const eps = epsForType(ty);
197 try expect(@cos(@as(ty, 0)) == 1);
198 try expect(math.approxEqAbs(ty, @cos(@as(ty, std.math.pi)), -1, eps));
199 try expect(math.approxEqAbs(ty, @cos(@as(ty, std.math.pi / 2)), 0, eps));
200 try expect(math.approxEqAbs(ty, @cos(@as(ty, std.math.pi / 4)), 0.7071067811865475, eps));
201 }
202}
203
204test "@exp" {
205 comptime try testExp();
206 try testExp();
207}
208
209fn testExp() !void {
210 inline for ([_]type{ f16, f32, f64 }) |ty| {
211 const eps = epsForType(ty);
212 try expect(@exp(@as(ty, 0)) == 1);
213 try expect(math.approxEqAbs(ty, @exp(@as(ty, 2)), 7.389056098930650, eps));
214 try expect(math.approxEqAbs(ty, @exp(@as(ty, 5)), 148.4131591025766, eps));
215 }
216
217 // TODO: Implement Vector support for other backends
218 if (builtin.zig_backend == .stage1) {
219 var v: Vector(4, f32) = [_]f32{ 1.1, 2.2, 0.3, 0.4 };
220 var result = @exp(v);
221 try expect(math.approxEqAbs(f32, @exp(@as(f32, 1.1)), result[0], epsilon));
222 try expect(math.approxEqAbs(f32, @exp(@as(f32, 2.2)), result[1], epsilon));
223 try expect(math.approxEqAbs(f32, @exp(@as(f32, 0.3)), result[2], epsilon));
224 try expect(math.approxEqAbs(f32, @exp(@as(f32, 0.4)), result[3], epsilon));
225 }
226}
227
228test "@exp2" {
229 comptime try testExp2();
230 try testExp2();
231}
232
233fn testExp2() !void {
234 inline for ([_]type{ f16, f32, f64 }) |ty| {
235 const eps = epsForType(ty);
236 try expect(@exp2(@as(ty, 2)) == 4);
237 try expect(math.approxEqAbs(ty, @exp2(@as(ty, 1.5)), 2.8284271247462, eps));
238 try expect(math.approxEqAbs(ty, @exp2(@as(ty, 4.5)), 22.627416997969, eps));
239 }
240
241 // TODO: Implement Vector support for other backends
242 if (builtin.zig_backend == .stage1) {
243 var v: Vector(4, f32) = [_]f32{ 1.1, 2.2, 0.3, 0.4 };
244 var result = @exp2(v);
245 try expect(math.approxEqAbs(f32, @exp2(@as(f32, 1.1)), result[0], epsilon));
246 try expect(math.approxEqAbs(f32, @exp2(@as(f32, 2.2)), result[1], epsilon));
247 try expect(math.approxEqAbs(f32, @exp2(@as(f32, 0.3)), result[2], epsilon));
248 try expect(math.approxEqAbs(f32, @exp2(@as(f32, 0.4)), result[3], epsilon));
249 }
250}
251
252test "@log" {
253 // Old musl (and glibc?), and our current math.ln implementation do not return 1
254 // so also accept those values.
255 comptime try testLog();
256 try testLog();
257}
258
259fn testLog() !void {
260 {
261 var a: f16 = e;
262 try expect(math.approxEqAbs(f16, @log(a), 1, epsilon));
263 }
264 {
265 var a: f32 = e;
266 try expect(@log(a) == 1 or @log(a) == @bitCast(f32, @as(u32, 0x3f7fffff)));
267 }
268 {
269 var a: f64 = e;
270 try expect(@log(a) == 1 or @log(a) == @bitCast(f64, @as(u64, 0x3ff0000000000000)));
271 }
272 inline for ([_]type{ f16, f32, f64 }) |ty| {
273 const eps = epsForType(ty);
274 try expect(math.approxEqAbs(ty, @log(@as(ty, 2)), 0.6931471805599, eps));
275 try expect(math.approxEqAbs(ty, @log(@as(ty, 5)), 1.6094379124341, eps));
276 }
277
278 // TODO: Implement Vector support for other backends
279 if (builtin.zig_backend == .stage1) {
280 var v: Vector(4, f32) = [_]f32{ 1.1, 2.2, 0.3, 0.4 };
281 var result = @log(v);
282 try expect(math.approxEqAbs(f32, @log(@as(f32, 1.1)), result[0], epsilon));
283 try expect(math.approxEqAbs(f32, @log(@as(f32, 2.2)), result[1], epsilon));
284 try expect(math.approxEqAbs(f32, @log(@as(f32, 0.3)), result[2], epsilon));
285 try expect(math.approxEqAbs(f32, @log(@as(f32, 0.4)), result[3], epsilon));
286 }
287}
288
289test "@log2" {
290 comptime try testLog2();
291 try testLog2();
292}
293
294fn testLog2() !void {
295 inline for ([_]type{ f16, f32, f64 }) |ty| {
296 const eps = epsForType(ty);
297 try expect(@log2(@as(ty, 4)) == 2);
298 try expect(math.approxEqAbs(ty, @log2(@as(ty, 6)), 2.5849625007212, eps));
299 try expect(math.approxEqAbs(ty, @log2(@as(ty, 10)), 3.3219280948874, eps));
300 }
301
302 // TODO: Implement Vector support for other backends
303 if (builtin.zig_backend == .stage1) {
304 var v: Vector(4, f32) = [_]f32{ 1.1, 2.2, 0.3, 0.4 };
305 var result = @log2(v);
306 try expect(math.approxEqAbs(f32, @log2(@as(f32, 1.1)), result[0], epsilon));
307 try expect(math.approxEqAbs(f32, @log2(@as(f32, 2.2)), result[1], epsilon));
308 try expect(math.approxEqAbs(f32, @log2(@as(f32, 0.3)), result[2], epsilon));
309 try expect(math.approxEqAbs(f32, @log2(@as(f32, 0.4)), result[3], epsilon));
310 }
311}
312
313test "@log10" {
314 comptime try testLog10();
315 try testLog10();
316}
317
318fn testLog10() !void {
319 inline for ([_]type{ f16, f32, f64 }) |ty| {
320 const eps = epsForType(ty);
321 try expect(@log10(@as(ty, 100)) == 2);
322 try expect(math.approxEqAbs(ty, @log10(@as(ty, 15)), 1.176091259056, eps));
323 try expect(math.approxEqAbs(ty, @log10(@as(ty, 50)), 1.698970004336, eps));
324 }
325
326 // TODO: Implement Vector support for other backends
327 if (builtin.zig_backend == .stage1) {
328 var v: Vector(4, f32) = [_]f32{ 1.1, 2.2, 0.3, 0.4 };
329 var result = @log10(v);
330 try expect(math.approxEqAbs(f32, @log10(@as(f32, 1.1)), result[0], epsilon));
331 try expect(math.approxEqAbs(f32, @log10(@as(f32, 2.2)), result[1], epsilon));
332 try expect(math.approxEqAbs(f32, @log10(@as(f32, 0.3)), result[2], epsilon));
333 try expect(math.approxEqAbs(f32, @log10(@as(f32, 0.4)), result[3], epsilon));
334 }
335}
336
337test "@fabs" {
338 comptime try testFabs();
339 try testFabs();
340}
341
342fn testFabs() !void {
343 try expect(@fabs(@as(f16, -2.5)) == 2.5);
344 try expect(@fabs(@as(f16, 2.5)) == 2.5);
345 try expect(@fabs(@as(f32, -2.5)) == 2.5);
346 try expect(@fabs(@as(f32, 2.5)) == 2.5);
347 try expect(@fabs(@as(f64, -2.5)) == 2.5);
348 try expect(@fabs(@as(f64, 2.5)) == 2.5);
349
350 // TODO test f128, and c_longdouble
351 // https://github.com/ziglang/zig/issues/4026
352 // {
353 // var a: f80 = -2.5;
354 // var b: f80 = 2.5;
355 // try expect(@fabs(a) == 2.5);
356 // try expect(@fabs(b) == 2.5);
357 // }
358
359 // TODO: Implement Vector support for other backends
360 if (builtin.zig_backend == .stage1) {
361 var v: Vector(4, f32) = [_]f32{ 1.1, -2.2, 0.3, -0.4 };
362 var result = @fabs(v);
363 try expect(math.approxEqAbs(f32, @fabs(@as(f32, 1.1)), result[0], epsilon));
364 try expect(math.approxEqAbs(f32, @fabs(@as(f32, -2.2)), result[1], epsilon));
365 try expect(math.approxEqAbs(f32, @fabs(@as(f32, 0.3)), result[2], epsilon));
366 try expect(math.approxEqAbs(f32, @fabs(@as(f32, -0.4)), result[3], epsilon));
367 }
368}
369
370test "@floor" {
371 comptime try testFloor();
372 try testFloor();
373}
374
375fn testFloor() !void {
376 try expect(@floor(@as(f16, 2.1)) == 2);
377 try expect(@floor(@as(f32, 2.1)) == 2);
378 try expect(@floor(@as(f64, 3.5)) == 3);
379
380 // TODO test f128, and c_longdouble
381 // https://github.com/ziglang/zig/issues/4026
382 // {
383 // var a: f80 = 3.5;
384 // try expect(@floor(a) == 3);
385 // }
386
387 // TODO: Implement Vector support for other backends
388 if (builtin.zig_backend == .stage1) {
389 var v: Vector(4, f32) = [_]f32{ 1.1, -2.2, 0.3, -0.4 };
390 var result = @floor(v);
391 try expect(math.approxEqAbs(f32, @floor(@as(f32, 1.1)), result[0], epsilon));
392 try expect(math.approxEqAbs(f32, @floor(@as(f32, -2.2)), result[1], epsilon));
393 try expect(math.approxEqAbs(f32, @floor(@as(f32, 0.3)), result[2], epsilon));
394 try expect(math.approxEqAbs(f32, @floor(@as(f32, -0.4)), result[3], epsilon));
395 }
396}
397
398test "@ceil" {
399 comptime try testCeil();
400 try testCeil();
401}
402
403fn testCeil() !void {
404 try expect(@ceil(@as(f16, 2.1)) == 3);
405 try expect(@ceil(@as(f32, 2.1)) == 3);
406 try expect(@ceil(@as(f64, 3.5)) == 4);
407
408 // TODO test f128, and c_longdouble
409 // https://github.com/ziglang/zig/issues/4026
410 // {
411 // var a: f80 = 3.5;
412 // try expect(@ceil(a) == 4);
413 // }
414
415 // TODO: Implement Vector support for other backends
416 if (builtin.zig_backend == .stage1) {
417 var v: Vector(4, f32) = [_]f32{ 1.1, -2.2, 0.3, -0.4 };
418 var result = @ceil(v);
419 try expect(math.approxEqAbs(f32, @ceil(@as(f32, 1.1)), result[0], epsilon));
420 try expect(math.approxEqAbs(f32, @ceil(@as(f32, -2.2)), result[1], epsilon));
421 try expect(math.approxEqAbs(f32, @ceil(@as(f32, 0.3)), result[2], epsilon));
422 try expect(math.approxEqAbs(f32, @ceil(@as(f32, -0.4)), result[3], epsilon));
423 }
424}
425
426test "@trunc" {
427 comptime try testTrunc();
428 try testTrunc();
429}
430
431fn testTrunc() !void {
432 try expect(@trunc(@as(f16, 2.1)) == 2);
433 try expect(@trunc(@as(f32, 2.1)) == 2);
434 try expect(@trunc(@as(f64, -3.5)) == -3);
435
436 // TODO test f128, and c_longdouble
437 // https://github.com/ziglang/zig/issues/4026
438 // {
439 // var a: f80 = -3.5;
440 // try expect(@trunc(a) == -3);
441 // }
442
443 // TODO: Implement Vector support for other backends
444 if (builtin.zig_backend == .stage1) {
445 var v: Vector(4, f32) = [_]f32{ 1.1, -2.2, 0.3, -0.4 };
446 var result = @trunc(v);
447 try expect(math.approxEqAbs(f32, @trunc(@as(f32, 1.1)), result[0], epsilon));
448 try expect(math.approxEqAbs(f32, @trunc(@as(f32, -2.2)), result[1], epsilon));
449 try expect(math.approxEqAbs(f32, @trunc(@as(f32, 0.3)), result[2], epsilon));
450 try expect(math.approxEqAbs(f32, @trunc(@as(f32, -0.4)), result[3], epsilon));
451 }
452}
test/behavior/floatop_stage1.zig deleted-452
......@@ -1,452 +0,0 @@
1const std = @import("std");
2const expect = std.testing.expect;
3const math = std.math;
4const pi = std.math.pi;
5const e = std.math.e;
6const Vector = std.meta.Vector;
7const has_f80_rt = @import("builtin").cpu.arch == .x86_64;
8
9const epsilon = 0.000001;
10
11test "@sqrt" {
12 comptime try testSqrt();
13 try testSqrt();
14}
15
16fn testSqrt() !void {
17 if (has_f80_rt) {
18 var a: f80 = 25;
19 try expect(@sqrt(a) == 5);
20 }
21 {
22 const a: comptime_float = 25.0;
23 try expect(@sqrt(a) == 5.0);
24 }
25 // TODO https://github.com/ziglang/zig/issues/4026
26 //{
27 // var a: f128 = 49;
28 //try expect(@sqrt(a) == 7);
29 //}
30 {
31 var v: Vector(4, f32) = [_]f32{ 1.1, 2.2, 3.3, 4.4 };
32 var result = @sqrt(v);
33 try expect(math.approxEqAbs(f32, @sqrt(@as(f32, 1.1)), result[0], epsilon));
34 try expect(math.approxEqAbs(f32, @sqrt(@as(f32, 2.2)), result[1], epsilon));
35 try expect(math.approxEqAbs(f32, @sqrt(@as(f32, 3.3)), result[2], epsilon));
36 try expect(math.approxEqAbs(f32, @sqrt(@as(f32, 4.4)), result[3], epsilon));
37 }
38}
39
40test "@sin" {
41 comptime try testSin();
42 try testSin();
43}
44
45fn testSin() !void {
46 // TODO test f128, and c_longdouble
47 // https://github.com/ziglang/zig/issues/4026
48 {
49 var a: f16 = 0;
50 try expect(@sin(a) == 0);
51 }
52 {
53 var a: f32 = 0;
54 try expect(@sin(a) == 0);
55 }
56 {
57 var a: f64 = 0;
58 try expect(@sin(a) == 0);
59 }
60 // {
61 // var a: f80 = 0;
62 // try expect(@sin(a) == 0);
63 // }
64 {
65 var v: Vector(4, f32) = [_]f32{ 1.1, 2.2, 3.3, 4.4 };
66 var result = @sin(v);
67 try expect(math.approxEqAbs(f32, @sin(@as(f32, 1.1)), result[0], epsilon));
68 try expect(math.approxEqAbs(f32, @sin(@as(f32, 2.2)), result[1], epsilon));
69 try expect(math.approxEqAbs(f32, @sin(@as(f32, 3.3)), result[2], epsilon));
70 try expect(math.approxEqAbs(f32, @sin(@as(f32, 4.4)), result[3], epsilon));
71 }
72}
73
74test "@cos" {
75 comptime try testCos();
76 try testCos();
77}
78
79fn testCos() !void {
80 // TODO test f128, and c_longdouble
81 // https://github.com/ziglang/zig/issues/4026
82 {
83 var a: f16 = 0;
84 try expect(@cos(a) == 1);
85 }
86 {
87 var a: f32 = 0;
88 try expect(@cos(a) == 1);
89 }
90 {
91 var a: f64 = 0;
92 try expect(@cos(a) == 1);
93 }
94 // {
95 // var a: f80 = 0;
96 // try expect(@cos(a) == 1);
97 // }
98 {
99 var v: Vector(4, f32) = [_]f32{ 1.1, 2.2, 3.3, 4.4 };
100 var result = @cos(v);
101 try expect(math.approxEqAbs(f32, @cos(@as(f32, 1.1)), result[0], epsilon));
102 try expect(math.approxEqAbs(f32, @cos(@as(f32, 2.2)), result[1], epsilon));
103 try expect(math.approxEqAbs(f32, @cos(@as(f32, 3.3)), result[2], epsilon));
104 try expect(math.approxEqAbs(f32, @cos(@as(f32, 4.4)), result[3], epsilon));
105 }
106}
107
108test "@exp" {
109 comptime try testExp();
110 try testExp();
111}
112
113fn testExp() !void {
114 // TODO test f128, and c_longdouble
115 // https://github.com/ziglang/zig/issues/4026
116 {
117 var a: f16 = 0;
118 try expect(@exp(a) == 1);
119 }
120 {
121 var a: f32 = 0;
122 try expect(@exp(a) == 1);
123 }
124 {
125 var a: f64 = 0;
126 try expect(@exp(a) == 1);
127 }
128 // {
129 // var a: f80 = 0;
130 // try expect(@exp(a) == 1);
131 // }
132 {
133 var v: Vector(4, f32) = [_]f32{ 1.1, 2.2, 0.3, 0.4 };
134 var result = @exp(v);
135 try expect(math.approxEqAbs(f32, @exp(@as(f32, 1.1)), result[0], epsilon));
136 try expect(math.approxEqAbs(f32, @exp(@as(f32, 2.2)), result[1], epsilon));
137 try expect(math.approxEqAbs(f32, @exp(@as(f32, 0.3)), result[2], epsilon));
138 try expect(math.approxEqAbs(f32, @exp(@as(f32, 0.4)), result[3], epsilon));
139 }
140}
141
142test "@exp2" {
143 comptime try testExp2();
144 try testExp2();
145}
146
147fn testExp2() !void {
148 // TODO test f128, and c_longdouble
149 // https://github.com/ziglang/zig/issues/4026
150 {
151 var a: f16 = 2;
152 try expect(@exp2(a) == 4);
153 }
154 {
155 var a: f32 = 2;
156 try expect(@exp2(a) == 4);
157 }
158 {
159 var a: f64 = 2;
160 try expect(@exp2(a) == 4);
161 }
162 // {
163 // var a: f80 = 2;
164 // try expect(@exp2(a) == 4);
165 // }
166 {
167 var v: Vector(4, f32) = [_]f32{ 1.1, 2.2, 0.3, 0.4 };
168 var result = @exp2(v);
169 try expect(math.approxEqAbs(f32, @exp2(@as(f32, 1.1)), result[0], epsilon));
170 try expect(math.approxEqAbs(f32, @exp2(@as(f32, 2.2)), result[1], epsilon));
171 try expect(math.approxEqAbs(f32, @exp2(@as(f32, 0.3)), result[2], epsilon));
172 try expect(math.approxEqAbs(f32, @exp2(@as(f32, 0.4)), result[3], epsilon));
173 }
174}
175
176test "@log" {
177 // Old musl (and glibc?), and our current math.ln implementation do not return 1
178 // so also accept those values.
179 comptime try testLog();
180 try testLog();
181}
182
183fn testLog() !void {
184 // TODO test f128, and c_longdouble
185 // https://github.com/ziglang/zig/issues/4026
186 {
187 var a: f16 = e;
188 try expect(math.approxEqAbs(f16, @log(a), 1, epsilon));
189 }
190 {
191 var a: f32 = e;
192 try expect(@log(a) == 1 or @log(a) == @bitCast(f32, @as(u32, 0x3f7fffff)));
193 }
194 {
195 var a: f64 = e;
196 try expect(@log(a) == 1 or @log(a) == @bitCast(f64, @as(u64, 0x3ff0000000000000)));
197 }
198 // {
199 // var a: f80 = e;
200 // try expect(@log(a) == 1);
201 // }
202 {
203 var v: Vector(4, f32) = [_]f32{ 1.1, 2.2, 0.3, 0.4 };
204 var result = @log(v);
205 try expect(math.approxEqAbs(f32, @log(@as(f32, 1.1)), result[0], epsilon));
206 try expect(math.approxEqAbs(f32, @log(@as(f32, 2.2)), result[1], epsilon));
207 try expect(math.approxEqAbs(f32, @log(@as(f32, 0.3)), result[2], epsilon));
208 try expect(math.approxEqAbs(f32, @log(@as(f32, 0.4)), result[3], epsilon));
209 }
210}
211
212test "@log2" {
213 comptime try testLog2();
214 try testLog2();
215}
216
217fn testLog2() !void {
218 // TODO test f128, and c_longdouble
219 // https://github.com/ziglang/zig/issues/4026
220 {
221 var a: f16 = 4;
222 try expect(@log2(a) == 2);
223 }
224 {
225 var a: f32 = 4;
226 try expect(@log2(a) == 2);
227 }
228 {
229 var a: f64 = 4;
230 try expect(@log2(a) == 2);
231 }
232 // {
233 // var a: f80 = 4;
234 // try expect(@log2(a) == 2);
235 // }
236 {
237 var v: Vector(4, f32) = [_]f32{ 1.1, 2.2, 0.3, 0.4 };
238 var result = @log2(v);
239 try expect(math.approxEqAbs(f32, @log2(@as(f32, 1.1)), result[0], epsilon));
240 try expect(math.approxEqAbs(f32, @log2(@as(f32, 2.2)), result[1], epsilon));
241 try expect(math.approxEqAbs(f32, @log2(@as(f32, 0.3)), result[2], epsilon));
242 try expect(math.approxEqAbs(f32, @log2(@as(f32, 0.4)), result[3], epsilon));
243 }
244}
245
246test "@log10" {
247 comptime try testLog10();
248 try testLog10();
249}
250
251fn testLog10() !void {
252 // TODO test f128, and c_longdouble
253 // https://github.com/ziglang/zig/issues/4026
254 {
255 var a: f16 = 100;
256 try expect(@log10(a) == 2);
257 }
258 {
259 var a: f32 = 100;
260 try expect(@log10(a) == 2);
261 }
262 {
263 var a: f64 = 1000;
264 try expect(@log10(a) == 3);
265 }
266 // {
267 // var a: f80 = 1000;
268 // try expect(@log10(a) == 3);
269 // }
270 {
271 var v: Vector(4, f32) = [_]f32{ 1.1, 2.2, 0.3, 0.4 };
272 var result = @log10(v);
273 try expect(math.approxEqAbs(f32, @log10(@as(f32, 1.1)), result[0], epsilon));
274 try expect(math.approxEqAbs(f32, @log10(@as(f32, 2.2)), result[1], epsilon));
275 try expect(math.approxEqAbs(f32, @log10(@as(f32, 0.3)), result[2], epsilon));
276 try expect(math.approxEqAbs(f32, @log10(@as(f32, 0.4)), result[3], epsilon));
277 }
278}
279
280test "@fabs" {
281 comptime try testFabs();
282 try testFabs();
283}
284
285fn testFabs() !void {
286 // TODO test f128, and c_longdouble
287 // https://github.com/ziglang/zig/issues/4026
288 {
289 var a: f16 = -2.5;
290 var b: f16 = 2.5;
291 try expect(@fabs(a) == 2.5);
292 try expect(@fabs(b) == 2.5);
293 }
294 {
295 var a: f32 = -2.5;
296 var b: f32 = 2.5;
297 try expect(@fabs(a) == 2.5);
298 try expect(@fabs(b) == 2.5);
299 }
300 {
301 var a: f64 = -2.5;
302 var b: f64 = 2.5;
303 try expect(@fabs(a) == 2.5);
304 try expect(@fabs(b) == 2.5);
305 }
306 // {
307 // var a: f80 = -2.5;
308 // var b: f80 = 2.5;
309 // try expect(@fabs(a) == 2.5);
310 // try expect(@fabs(b) == 2.5);
311 // }
312 {
313 var v: Vector(4, f32) = [_]f32{ 1.1, -2.2, 0.3, -0.4 };
314 var result = @fabs(v);
315 try expect(math.approxEqAbs(f32, @fabs(@as(f32, 1.1)), result[0], epsilon));
316 try expect(math.approxEqAbs(f32, @fabs(@as(f32, -2.2)), result[1], epsilon));
317 try expect(math.approxEqAbs(f32, @fabs(@as(f32, 0.3)), result[2], epsilon));
318 try expect(math.approxEqAbs(f32, @fabs(@as(f32, -0.4)), result[3], epsilon));
319 }
320}
321
322test "@floor" {
323 comptime try testFloor();
324 try testFloor();
325}
326
327fn testFloor() !void {
328 // TODO test f128, and c_longdouble
329 // https://github.com/ziglang/zig/issues/4026
330 {
331 var a: f16 = 2.1;
332 try expect(@floor(a) == 2);
333 }
334 {
335 var a: f32 = 2.1;
336 try expect(@floor(a) == 2);
337 }
338 {
339 var a: f64 = 3.5;
340 try expect(@floor(a) == 3);
341 }
342 // {
343 // var a: f80 = 3.5;
344 // try expect(@floor(a) == 3);
345 // }
346 {
347 var v: Vector(4, f32) = [_]f32{ 1.1, -2.2, 0.3, -0.4 };
348 var result = @floor(v);
349 try expect(math.approxEqAbs(f32, @floor(@as(f32, 1.1)), result[0], epsilon));
350 try expect(math.approxEqAbs(f32, @floor(@as(f32, -2.2)), result[1], epsilon));
351 try expect(math.approxEqAbs(f32, @floor(@as(f32, 0.3)), result[2], epsilon));
352 try expect(math.approxEqAbs(f32, @floor(@as(f32, -0.4)), result[3], epsilon));
353 }
354}
355
356test "@ceil" {
357 comptime try testCeil();
358 try testCeil();
359}
360
361fn testCeil() !void {
362 // TODO test f128, and c_longdouble
363 // https://github.com/ziglang/zig/issues/4026
364 {
365 var a: f16 = 2.1;
366 try expect(@ceil(a) == 3);
367 }
368 {
369 var a: f32 = 2.1;
370 try expect(@ceil(a) == 3);
371 }
372 {
373 var a: f64 = 3.5;
374 try expect(@ceil(a) == 4);
375 }
376 // {
377 // var a: f80 = 3.5;
378 // try expect(@ceil(a) == 4);
379 // }
380 {
381 var v: Vector(4, f32) = [_]f32{ 1.1, -2.2, 0.3, -0.4 };
382 var result = @ceil(v);
383 try expect(math.approxEqAbs(f32, @ceil(@as(f32, 1.1)), result[0], epsilon));
384 try expect(math.approxEqAbs(f32, @ceil(@as(f32, -2.2)), result[1], epsilon));
385 try expect(math.approxEqAbs(f32, @ceil(@as(f32, 0.3)), result[2], epsilon));
386 try expect(math.approxEqAbs(f32, @ceil(@as(f32, -0.4)), result[3], epsilon));
387 }
388}
389
390test "@trunc" {
391 comptime try testTrunc();
392 try testTrunc();
393}
394
395fn testTrunc() !void {
396 // TODO test f128, and c_longdouble
397 // https://github.com/ziglang/zig/issues/4026
398 {
399 var a: f16 = 2.1;
400 try expect(@trunc(a) == 2);
401 }
402 {
403 var a: f32 = 2.1;
404 try expect(@trunc(a) == 2);
405 }
406 {
407 var a: f64 = -3.5;
408 try expect(@trunc(a) == -3);
409 }
410 // {
411 // var a: f80 = -3.5;
412 // try expect(@trunc(a) == -3);
413 // }
414 {
415 var v: Vector(4, f32) = [_]f32{ 1.1, -2.2, 0.3, -0.4 };
416 var result = @trunc(v);
417 try expect(math.approxEqAbs(f32, @trunc(@as(f32, 1.1)), result[0], epsilon));
418 try expect(math.approxEqAbs(f32, @trunc(@as(f32, -2.2)), result[1], epsilon));
419 try expect(math.approxEqAbs(f32, @trunc(@as(f32, 0.3)), result[2], epsilon));
420 try expect(math.approxEqAbs(f32, @trunc(@as(f32, -0.4)), result[3], epsilon));
421 }
422}
423
424test "floating point comparisons" {
425 if (has_f80_rt) try testFloatComparisons();
426 comptime try testFloatComparisons();
427}
428
429fn testFloatComparisons() !void {
430 inline for ([_]type{ f16, f32, f64, f80, f128 }) |ty| {
431 // No decimal part
432 {
433 const x: ty = 1.0;
434 try expect(x == 1);
435 try expect(x != 0);
436 try expect(x > 0);
437 try expect(x < 2);
438 try expect(x >= 1);
439 try expect(x <= 1);
440 }
441 // Non-zero decimal part
442 {
443 const x: ty = 1.5;
444 try expect(x != 1);
445 try expect(x != 2);
446 try expect(x > 1);
447 try expect(x < 2);
448 try expect(x >= 1);
449 try expect(x <= 2);
450 }
451 }
452}