Skip to content

Instantly share code, notes, and snippets.

@matu3ba
Last active December 17, 2021 05:59
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save matu3ba/ca26361231d21b0ca0f79b0f2753c92d to your computer and use it in GitHub Desktop.
Save matu3ba/ca26361231d21b0ca0f79b0f2753c92d to your computer and use it in GitHub Desktop.
abs implementations
// Observation: only MIN has no abs
// 2s complement is ~x+1
// 2s compl of MIN == MIN, since ~0b100..00 + 1 == 0b011..11 + 1 == 0b100..00
// NOTE: 2s complement of 0 would overflow ~0x00..00 + 1 == 0xff..ff + 1 kaboom
// working version
fn absvXi_generic(comptime ST: type) fn (a: ST) callconv(.C) ST {
return struct {
fn f(a: ST) callconv(.C) ST {
var x = a;
if (x < 0) {
x = ~x +% 1; // 2s complement
if (x < 0) // did we overflow?
return -1;
}
return x;
}
}.f;
}
// LLVM version (not optimal)
fn absvXi_generic(comptime ST: type) fn (a: ST) callconv(.C) ST {
return struct {
fn f(a: ST) callconv(.C) ST {
const UT = switch (ST) {
i32 => u32,
i64 => u64,
i128 => u128,
else => unreachable,
};
const N: UT = @bitSizeOf(ST);
const min: ST = @bitCast(ST, (@as(UT, 1) << (N - 1)));
if (a == min)
return -1; // replace with @panic("abs: overflow");
const sign: ST = a >> (N - 1);
return (a ^ sign) - sign;
}
}.f;
}
// optimal version in software
fn absvXi_generic(comptime ST: type) fn (a: ST) callconv(.C) ST {
return struct {
fn f(a: ST) callconv(.C) ST {
const UT = switch (ST) {
i32 => u32,
i64 => u64,
i128 => u128,
else => unreachable,
};
var x: ST = a;
const N: UT = @bitSizeOf(ST);
const sign: ST = a >> N - 1;
x +%= sign;
x ^= sign;
if (x < 0)
return -1; // replace with @panic("abs: overflow"); instead
return x;
}
}.f;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment