mirror of
https://github.com/ziglang/zig.git
synced 2025-12-06 06:13:07 +00:00
When exporting math functions for Windows, we provide weak exports of 'l' variants rather than weak aliases. We still use aliases on other operating systems so that the 'l' variants have one less jump instruction in this case.
166 lines
4.0 KiB
Zig
166 lines
4.0 KiB
Zig
// Ported from musl, which is licensed under the MIT license:
|
|
// https://git.musl-libc.org/cgit/musl/tree/COPYRIGHT
|
|
//
|
|
// https://git.musl-libc.org/cgit/musl/tree/src/math/ceilf.c
|
|
// https://git.musl-libc.org/cgit/musl/tree/src/math/ceil.c
|
|
|
|
const std = @import("std");
|
|
const math = std.math;
|
|
const expect = std.testing.expect;
|
|
|
|
pub fn __ceilh(x: f16) callconv(.C) f16 {
|
|
// TODO: more efficient implementation
|
|
return @floatCast(f16, ceilf(x));
|
|
}
|
|
|
|
pub fn ceilf(x: f32) callconv(.C) f32 {
|
|
var u = @bitCast(u32, x);
|
|
var e = @intCast(i32, (u >> 23) & 0xFF) - 0x7F;
|
|
var m: u32 = undefined;
|
|
|
|
// TODO: Shouldn't need this explicit check.
|
|
if (x == 0.0) {
|
|
return x;
|
|
}
|
|
|
|
if (e >= 23) {
|
|
return x;
|
|
} else if (e >= 0) {
|
|
m = @as(u32, 0x007FFFFF) >> @intCast(u5, e);
|
|
if (u & m == 0) {
|
|
return x;
|
|
}
|
|
math.doNotOptimizeAway(x + 0x1.0p120);
|
|
if (u >> 31 == 0) {
|
|
u += m;
|
|
}
|
|
u &= ~m;
|
|
return @bitCast(f32, u);
|
|
} else {
|
|
math.doNotOptimizeAway(x + 0x1.0p120);
|
|
if (u >> 31 != 0) {
|
|
return -0.0;
|
|
} else {
|
|
return 1.0;
|
|
}
|
|
}
|
|
}
|
|
|
|
pub fn ceil(x: f64) callconv(.C) f64 {
|
|
const f64_toint = 1.0 / math.floatEps(f64);
|
|
|
|
const u = @bitCast(u64, x);
|
|
const e = (u >> 52) & 0x7FF;
|
|
var y: f64 = undefined;
|
|
|
|
if (e >= 0x3FF + 52 or x == 0) {
|
|
return x;
|
|
}
|
|
|
|
if (u >> 63 != 0) {
|
|
y = x - f64_toint + f64_toint - x;
|
|
} else {
|
|
y = x + f64_toint - f64_toint - x;
|
|
}
|
|
|
|
if (e <= 0x3FF - 1) {
|
|
math.doNotOptimizeAway(y);
|
|
if (u >> 63 != 0) {
|
|
return -0.0;
|
|
} else {
|
|
return 1.0;
|
|
}
|
|
} else if (y < 0) {
|
|
return x + y + 1;
|
|
} else {
|
|
return x + y;
|
|
}
|
|
}
|
|
|
|
pub fn __ceilx(x: f80) callconv(.C) f80 {
|
|
// TODO: more efficient implementation
|
|
return @floatCast(f80, ceilq(x));
|
|
}
|
|
|
|
pub fn ceilq(x: f128) callconv(.C) f128 {
|
|
const f128_toint = 1.0 / math.floatEps(f128);
|
|
|
|
const u = @bitCast(u128, x);
|
|
const e = (u >> 112) & 0x7FFF;
|
|
var y: f128 = undefined;
|
|
|
|
if (e >= 0x3FFF + 112 or x == 0) return x;
|
|
|
|
if (u >> 127 != 0) {
|
|
y = x - f128_toint + f128_toint - x;
|
|
} else {
|
|
y = x + f128_toint - f128_toint - x;
|
|
}
|
|
|
|
if (e <= 0x3FFF - 1) {
|
|
math.doNotOptimizeAway(y);
|
|
if (u >> 127 != 0) {
|
|
return -0.0;
|
|
} else {
|
|
return 1.0;
|
|
}
|
|
} else if (y < 0) {
|
|
return x + y + 1;
|
|
} else {
|
|
return x + y;
|
|
}
|
|
}
|
|
|
|
pub fn ceill(x: c_longdouble) callconv(.C) c_longdouble {
|
|
switch (@typeInfo(c_longdouble).Float.bits) {
|
|
16 => return __ceilh(x),
|
|
32 => return ceilf(x),
|
|
64 => return ceil(x),
|
|
80 => return __ceilx(x),
|
|
128 => return ceilq(x),
|
|
else => @compileError("unreachable"),
|
|
}
|
|
}
|
|
|
|
test "ceil32" {
|
|
try expect(ceilf(1.3) == 2.0);
|
|
try expect(ceilf(-1.3) == -1.0);
|
|
try expect(ceilf(0.2) == 1.0);
|
|
}
|
|
|
|
test "ceil64" {
|
|
try expect(ceil(1.3) == 2.0);
|
|
try expect(ceil(-1.3) == -1.0);
|
|
try expect(ceil(0.2) == 1.0);
|
|
}
|
|
|
|
test "ceil128" {
|
|
try expect(ceilq(1.3) == 2.0);
|
|
try expect(ceilq(-1.3) == -1.0);
|
|
try expect(ceilq(0.2) == 1.0);
|
|
}
|
|
|
|
test "ceil32.special" {
|
|
try expect(ceilf(0.0) == 0.0);
|
|
try expect(ceilf(-0.0) == -0.0);
|
|
try expect(math.isPositiveInf(ceilf(math.inf(f32))));
|
|
try expect(math.isNegativeInf(ceilf(-math.inf(f32))));
|
|
try expect(math.isNan(ceilf(math.nan(f32))));
|
|
}
|
|
|
|
test "ceil64.special" {
|
|
try expect(ceil(0.0) == 0.0);
|
|
try expect(ceil(-0.0) == -0.0);
|
|
try expect(math.isPositiveInf(ceil(math.inf(f64))));
|
|
try expect(math.isNegativeInf(ceil(-math.inf(f64))));
|
|
try expect(math.isNan(ceil(math.nan(f64))));
|
|
}
|
|
|
|
test "ceil128.special" {
|
|
try expect(ceilq(0.0) == 0.0);
|
|
try expect(ceilq(-0.0) == -0.0);
|
|
try expect(math.isPositiveInf(ceilq(math.inf(f128))));
|
|
try expect(math.isNegativeInf(ceilq(-math.inf(f128))));
|
|
try expect(math.isNan(ceilq(math.nan(f128))));
|
|
}
|