Files
Odin/core/math/big/logical.odin
T
2021-08-11 20:59:54 +02:00

144 lines
4.4 KiB
Odin

package math_big
/*
Copyright 2021 Jeroen van Rijn <nom@duclavier.com>.
Made available under Odin's BSD-2 license.
An arbitrary precision mathematics implementation in Odin.
For the theoretical underpinnings, see Knuth's The Art of Computer Programming, Volume 2, section 4.3.
The code started out as an idiomatic source port of libTomMath, which is in the public domain, with thanks.
This file contains logical operations like `and`, `or` and `xor`.
*/
/*
The `and`, `or` and `xor` binops differ in two lines only.
We could handle those with a switch, but that adds overhead.
TODO: Implement versions that take a DIGIT immediate.
*/
/*
2's complement `and`, returns `dest = a & b;`
*/
int_and :: proc(dest, a, b: ^Int, allocator := context.allocator) -> (err: Error) {
assert_if_nil(dest, a, b);
context.allocator = allocator;
if err = internal_clear_if_uninitialized(a, b); err != nil { return err; }
return #force_inline internal_int_and(dest, a, b);
}
and :: proc { int_and, };
/*
2's complement `or`, returns `dest = a | b;`
*/
int_or :: proc(dest, a, b: ^Int, allocator := context.allocator) -> (err: Error) {
assert_if_nil(dest, a, b);
context.allocator = allocator;
if err = internal_clear_if_uninitialized(a, b); err != nil { return err; }
return #force_inline internal_int_or(dest, a, b);
}
or :: proc { int_or, };
/*
2's complement `xor`, returns `dest = a ^ b;`
*/
int_xor :: proc(dest, a, b: ^Int, allocator := context.allocator) -> (err: Error) {
assert_if_nil(dest, a, b);
context.allocator = allocator;
if err = internal_clear_if_uninitialized(a, b); err != nil { return err; }
return #force_inline internal_int_xor(dest, a, b);
}
xor :: proc { int_xor, };
/*
dest = ~src
*/
int_complement :: proc(dest, src: ^Int, allocator := context.allocator) -> (err: Error) {
/*
Check that `src` and `dest` are usable.
*/
assert_if_nil(dest, src);
context.allocator = allocator;
if err = internal_clear_if_uninitialized(dest, src); err != nil { return err; }
return #force_inline internal_int_complement(dest, src);
}
complement :: proc { int_complement, };
/*
quotient, remainder := numerator >> bits;
`remainder` is allowed to be passed a `nil`, in which case `mod` won't be computed.
*/
int_shrmod :: proc(quotient, remainder, numerator: ^Int, bits: int, allocator := context.allocator) -> (err: Error) {
assert_if_nil(quotient, numerator);
context.allocator = allocator;
if err = internal_clear_if_uninitialized(quotient, numerator); err != nil { return err; }
return #force_inline internal_int_shrmod(quotient, remainder, numerator, bits);
}
shrmod :: proc { int_shrmod, };
int_shr :: proc(dest, source: ^Int, bits: int, allocator := context.allocator) -> (err: Error) {
return #force_inline shrmod(dest, nil, source, bits, allocator);
}
shr :: proc { int_shr, };
/*
Shift right by `digits` * _DIGIT_BITS bits.
*/
int_shr_digit :: proc(quotient: ^Int, digits: int, allocator := context.allocator) -> (err: Error) {
/*
Check that `quotient` is usable.
*/
assert_if_nil(quotient);
context.allocator = allocator;
if err = internal_clear_if_uninitialized(quotient); err != nil { return err; }
return #force_inline internal_int_shr_digit(quotient, digits);
}
shr_digit :: proc { int_shr_digit, };
/*
Shift right by a certain bit count with sign extension.
*/
int_shr_signed :: proc(dest, src: ^Int, bits: int, allocator := context.allocator) -> (err: Error) {
assert_if_nil(dest, src);
context.allocator = allocator;
if err = internal_clear_if_uninitialized(dest, src); err != nil { return err; }
return #force_inline internal_int_shr_signed(dest, src, bits);
}
shr_signed :: proc { int_shr_signed, };
/*
Shift left by a certain bit count.
*/
int_shl :: proc(dest, src: ^Int, bits: int, allocator := context.allocator) -> (err: Error) {
assert_if_nil(dest, src);
context.allocator = allocator;
if err = internal_clear_if_uninitialized(dest, src); err != nil { return err; }
return #force_inline internal_int_shl(dest, src, bits);
}
shl :: proc { int_shl, };
/*
Shift left by `digits` * _DIGIT_BITS bits.
*/
int_shl_digit :: proc(quotient: ^Int, digits: int, allocator := context.allocator) -> (err: Error) {
/*
Check that `quotient` is usable.
*/
assert_if_nil(quotient);
context.allocator = allocator;
if err = internal_clear_if_uninitialized(quotient); err != nil { return err; }
return #force_inline internal_int_shl_digit(quotient, digits);
}
shl_digit :: proc { int_shl_digit, };