master
  1//! Ported from musl, which is MIT licensed.
  2//! https://git.musl-libc.org/cgit/musl/tree/COPYRIGHT
  3//!
  4//! https://git.musl-libc.org/cgit/musl/tree/src/math/truncf.c
  5//! https://git.musl-libc.org/cgit/musl/tree/src/math/trunc.c
  6
  7const std = @import("std");
  8const builtin = @import("builtin");
  9const arch = builtin.cpu.arch;
 10const math = std.math;
 11const mem = std.mem;
 12const expect = std.testing.expect;
 13const common = @import("common.zig");
 14
 15pub const panic = common.panic;
 16
 17comptime {
 18    @export(&__trunch, .{ .name = "__trunch", .linkage = common.linkage, .visibility = common.visibility });
 19    @export(&truncf, .{ .name = "truncf", .linkage = common.linkage, .visibility = common.visibility });
 20    @export(&trunc, .{ .name = "trunc", .linkage = common.linkage, .visibility = common.visibility });
 21    @export(&__truncx, .{ .name = "__truncx", .linkage = common.linkage, .visibility = common.visibility });
 22    if (common.want_ppc_abi) {
 23        @export(&truncq, .{ .name = "truncf128", .linkage = common.linkage, .visibility = common.visibility });
 24    }
 25    @export(&truncq, .{ .name = "truncq", .linkage = common.linkage, .visibility = common.visibility });
 26    @export(&truncl, .{ .name = "truncl", .linkage = common.linkage, .visibility = common.visibility });
 27}
 28
 29pub fn __trunch(x: f16) callconv(.c) f16 {
 30    // TODO: more efficient implementation
 31    return @floatCast(truncf(x));
 32}
 33
 34pub fn truncf(x: f32) callconv(.c) f32 {
 35    const u: u32 = @bitCast(x);
 36    var e = @as(i32, @intCast(((u >> 23) & 0xFF))) - 0x7F + 9;
 37    var m: u32 = undefined;
 38
 39    if (e >= 23 + 9) {
 40        return x;
 41    }
 42    if (e < 9) {
 43        e = 1;
 44    }
 45
 46    m = @as(u32, math.maxInt(u32)) >> @intCast(e);
 47    if (u & m == 0) {
 48        return x;
 49    } else {
 50        if (common.want_float_exceptions) mem.doNotOptimizeAway(x + 0x1p120);
 51        return @bitCast(u & ~m);
 52    }
 53}
 54
 55pub fn trunc(x: f64) callconv(.c) f64 {
 56    const u: u64 = @bitCast(x);
 57    var e = @as(i32, @intCast(((u >> 52) & 0x7FF))) - 0x3FF + 12;
 58    var m: u64 = undefined;
 59
 60    if (e >= 52 + 12) {
 61        return x;
 62    }
 63    if (e < 12) {
 64        e = 1;
 65    }
 66
 67    m = @as(u64, math.maxInt(u64)) >> @intCast(e);
 68    if (u & m == 0) {
 69        return x;
 70    } else {
 71        if (common.want_float_exceptions) mem.doNotOptimizeAway(x + 0x1p120);
 72        return @bitCast(u & ~m);
 73    }
 74}
 75
 76pub fn __truncx(x: f80) callconv(.c) f80 {
 77    // TODO: more efficient implementation
 78    return @floatCast(truncq(x));
 79}
 80
 81pub fn truncq(x: f128) callconv(.c) f128 {
 82    const u: u128 = @bitCast(x);
 83    var e = @as(i32, @intCast(((u >> 112) & 0x7FFF))) - 0x3FFF + 16;
 84    var m: u128 = undefined;
 85
 86    if (e >= 112 + 16) {
 87        return x;
 88    }
 89    if (e < 16) {
 90        e = 1;
 91    }
 92
 93    m = @as(u128, math.maxInt(u128)) >> @intCast(e);
 94    if (u & m == 0) {
 95        return x;
 96    } else {
 97        if (common.want_float_exceptions) mem.doNotOptimizeAway(x + 0x1p120);
 98        return @bitCast(u & ~m);
 99    }
100}
101
102pub fn truncl(x: c_longdouble) callconv(.c) c_longdouble {
103    switch (@typeInfo(c_longdouble).float.bits) {
104        16 => return __trunch(x),
105        32 => return truncf(x),
106        64 => return trunc(x),
107        80 => return __truncx(x),
108        128 => return truncq(x),
109        else => @compileError("unreachable"),
110    }
111}
112
113test "trunc32" {
114    try expect(truncf(1.3) == 1.0);
115    try expect(truncf(-1.3) == -1.0);
116    try expect(truncf(0.2) == 0.0);
117}
118
119test "trunc64" {
120    try expect(trunc(1.3) == 1.0);
121    try expect(trunc(-1.3) == -1.0);
122    try expect(trunc(0.2) == 0.0);
123}
124
125test "trunc128" {
126    try expect(truncq(1.3) == 1.0);
127    try expect(truncq(-1.3) == -1.0);
128    try expect(truncq(0.2) == 0.0);
129}
130
131test "trunc32.special" {
132    try expect(truncf(0.0) == 0.0); // 0x3F800000
133    try expect(truncf(-0.0) == -0.0);
134    try expect(math.isPositiveInf(truncf(math.inf(f32))));
135    try expect(math.isNegativeInf(truncf(-math.inf(f32))));
136    try expect(math.isNan(truncf(math.nan(f32))));
137}
138
139test "trunc64.special" {
140    try expect(trunc(0.0) == 0.0);
141    try expect(trunc(-0.0) == -0.0);
142    try expect(math.isPositiveInf(trunc(math.inf(f64))));
143    try expect(math.isNegativeInf(trunc(-math.inf(f64))));
144    try expect(math.isNan(trunc(math.nan(f64))));
145}
146
147test "trunc128.special" {
148    try expect(truncq(0.0) == 0.0);
149    try expect(truncq(-0.0) == -0.0);
150    try expect(math.isPositiveInf(truncq(math.inf(f128))));
151    try expect(math.isNegativeInf(truncq(-math.inf(f128))));
152    try expect(math.isNan(truncq(math.nan(f128))));
153}