zig

fork of https://codeberg.org/ziglang/zig
Log | Files | Refs | README | LICENSE

floor.zig (6290B) - Raw


      1 //! Ported from musl, which is licensed under the MIT license:
      2 //! https://git.musl-libc.org/cgit/musl/tree/COPYRIGHT
      3 //!
      4 //! https://git.musl-libc.org/cgit/musl/tree/src/math/floorf.c
      5 //! https://git.musl-libc.org/cgit/musl/tree/src/math/floor.c
      6 
      7 const std = @import("std");
      8 const builtin = @import("builtin");
      9 const math = std.math;
     10 const mem = std.mem;
     11 const expect = std.testing.expect;
     12 const arch = builtin.cpu.arch;
     13 const common = @import("common.zig");
     14 
     15 pub const panic = common.panic;
     16 
     17 comptime {
     18     @export(&__floorh, .{ .name = "__floorh", .linkage = common.linkage, .visibility = common.visibility });
     19     @export(&floorf, .{ .name = "floorf", .linkage = common.linkage, .visibility = common.visibility });
     20     @export(&floor, .{ .name = "floor", .linkage = common.linkage, .visibility = common.visibility });
     21     @export(&__floorx, .{ .name = "__floorx", .linkage = common.linkage, .visibility = common.visibility });
     22     if (common.want_ppc_abi) {
     23         @export(&floorq, .{ .name = "floorf128", .linkage = common.linkage, .visibility = common.visibility });
     24     }
     25     @export(&floorq, .{ .name = "floorq", .linkage = common.linkage, .visibility = common.visibility });
     26     @export(&floorl, .{ .name = "floorl", .linkage = common.linkage, .visibility = common.visibility });
     27 }
     28 
     29 pub fn __floorh(x: f16) callconv(.c) f16 {
     30     var u: u16 = @bitCast(x);
     31     const e = @as(i16, @intCast((u >> 10) & 31)) - 15;
     32     var m: u16 = undefined;
     33 
     34     // TODO: Shouldn't need this explicit check.
     35     if (x == 0.0) {
     36         return x;
     37     }
     38 
     39     if (e >= 10) {
     40         return x;
     41     }
     42 
     43     if (e >= 0) {
     44         m = @as(u16, 1023) >> @intCast(e);
     45         if (u & m == 0) {
     46             return x;
     47         }
     48         if (common.want_float_exceptions) mem.doNotOptimizeAway(x + 0x1.0p120);
     49         if (u >> 15 != 0) {
     50             u += m;
     51         }
     52         return @bitCast(u & ~m);
     53     } else {
     54         if (common.want_float_exceptions) mem.doNotOptimizeAway(x + 0x1.0p120);
     55         if (u >> 15 == 0) {
     56             return 0.0;
     57         } else {
     58             return -1.0;
     59         }
     60     }
     61 }
     62 
     63 pub fn floorf(x: f32) callconv(.c) f32 {
     64     var u: u32 = @bitCast(x);
     65     const e = @as(i32, @intCast((u >> 23) & 0xFF)) - 0x7F;
     66     var m: u32 = undefined;
     67 
     68     // TODO: Shouldn't need this explicit check.
     69     if (x == 0.0) {
     70         return x;
     71     }
     72 
     73     if (e >= 23) {
     74         return x;
     75     }
     76 
     77     if (e >= 0) {
     78         m = @as(u32, 0x007FFFFF) >> @intCast(e);
     79         if (u & m == 0) {
     80             return x;
     81         }
     82         if (common.want_float_exceptions) mem.doNotOptimizeAway(x + 0x1.0p120);
     83         if (u >> 31 != 0) {
     84             u += m;
     85         }
     86         return @bitCast(u & ~m);
     87     } else {
     88         if (common.want_float_exceptions) mem.doNotOptimizeAway(x + 0x1.0p120);
     89         if (u >> 31 == 0) {
     90             return 0.0;
     91         } else {
     92             return -1.0;
     93         }
     94     }
     95 }
     96 
     97 pub fn floor(x: f64) callconv(.c) f64 {
     98     const f64_toint = 1.0 / math.floatEps(f64);
     99 
    100     const u: u64 = @bitCast(x);
    101     const e = (u >> 52) & 0x7FF;
    102     var y: f64 = undefined;
    103 
    104     if (e >= 0x3FF + 52 or x == 0) {
    105         return x;
    106     }
    107 
    108     if (u >> 63 != 0) {
    109         y = x - f64_toint + f64_toint - x;
    110     } else {
    111         y = x + f64_toint - f64_toint - x;
    112     }
    113 
    114     if (e <= 0x3FF - 1) {
    115         if (common.want_float_exceptions) mem.doNotOptimizeAway(y);
    116         if (u >> 63 != 0) {
    117             return -1.0;
    118         } else {
    119             return 0.0;
    120         }
    121     } else if (y > 0) {
    122         return x + y - 1;
    123     } else {
    124         return x + y;
    125     }
    126 }
    127 
    128 pub fn __floorx(x: f80) callconv(.c) f80 {
    129     // TODO: more efficient implementation
    130     return @floatCast(floorq(x));
    131 }
    132 
    133 pub fn floorq(x: f128) callconv(.c) f128 {
    134     const f128_toint = 1.0 / math.floatEps(f128);
    135 
    136     const u: u128 = @bitCast(x);
    137     const e = (u >> 112) & 0x7FFF;
    138     var y: f128 = undefined;
    139 
    140     if (e >= 0x3FFF + 112 or x == 0) return x;
    141 
    142     if (u >> 127 != 0) {
    143         y = x - f128_toint + f128_toint - x;
    144     } else {
    145         y = x + f128_toint - f128_toint - x;
    146     }
    147 
    148     if (e <= 0x3FFF - 1) {
    149         if (common.want_float_exceptions) mem.doNotOptimizeAway(y);
    150         if (u >> 127 != 0) {
    151             return -1.0;
    152         } else {
    153             return 0.0;
    154         }
    155     } else if (y > 0) {
    156         return x + y - 1;
    157     } else {
    158         return x + y;
    159     }
    160 }
    161 
    162 pub fn floorl(x: c_longdouble) callconv(.c) c_longdouble {
    163     switch (@typeInfo(c_longdouble).float.bits) {
    164         16 => return __floorh(x),
    165         32 => return floorf(x),
    166         64 => return floor(x),
    167         80 => return __floorx(x),
    168         128 => return floorq(x),
    169         else => @compileError("unreachable"),
    170     }
    171 }
    172 
    173 test "floor16" {
    174     try expect(__floorh(1.3) == 1.0);
    175     try expect(__floorh(-1.3) == -2.0);
    176     try expect(__floorh(0.2) == 0.0);
    177 }
    178 
    179 test "floor32" {
    180     try expect(floorf(1.3) == 1.0);
    181     try expect(floorf(-1.3) == -2.0);
    182     try expect(floorf(0.2) == 0.0);
    183 }
    184 
    185 test "floor64" {
    186     try expect(floor(1.3) == 1.0);
    187     try expect(floor(-1.3) == -2.0);
    188     try expect(floor(0.2) == 0.0);
    189 }
    190 
    191 test "floor128" {
    192     try expect(floorq(1.3) == 1.0);
    193     try expect(floorq(-1.3) == -2.0);
    194     try expect(floorq(0.2) == 0.0);
    195 }
    196 
    197 test "floor16.special" {
    198     try expect(__floorh(0.0) == 0.0);
    199     try expect(__floorh(-0.0) == -0.0);
    200     try expect(math.isPositiveInf(__floorh(math.inf(f16))));
    201     try expect(math.isNegativeInf(__floorh(-math.inf(f16))));
    202     try expect(math.isNan(__floorh(math.nan(f16))));
    203 }
    204 
    205 test "floor32.special" {
    206     try expect(floorf(0.0) == 0.0);
    207     try expect(floorf(-0.0) == -0.0);
    208     try expect(math.isPositiveInf(floorf(math.inf(f32))));
    209     try expect(math.isNegativeInf(floorf(-math.inf(f32))));
    210     try expect(math.isNan(floorf(math.nan(f32))));
    211 }
    212 
    213 test "floor64.special" {
    214     try expect(floor(0.0) == 0.0);
    215     try expect(floor(-0.0) == -0.0);
    216     try expect(math.isPositiveInf(floor(math.inf(f64))));
    217     try expect(math.isNegativeInf(floor(-math.inf(f64))));
    218     try expect(math.isNan(floor(math.nan(f64))));
    219 }
    220 
    221 test "floor128.special" {
    222     try expect(floorq(0.0) == 0.0);
    223     try expect(floorq(-0.0) == -0.0);
    224     try expect(math.isPositiveInf(floorq(math.inf(f128))));
    225     try expect(math.isNegativeInf(floorq(-math.inf(f128))));
    226     try expect(math.isNan(floorq(math.nan(f128))));
    227 }