浏览代码

bigint: Add `count_bits` and more prep.

Jeroen van Rijn 4 年之前
父节点
当前提交
905d5459a9
共有 4 个文件被更改,包括 41 次插入20 次删除
  1. 0 1
      core/math/bigint/basic.odin
  2. 15 16
      core/math/bigint/bigint.odin
  3. 3 3
      core/math/bigint/example.odin
  4. 23 0
      core/math/bigint/helpers.odin

+ 0 - 1
core/math/bigint/basic.odin

@@ -89,7 +89,6 @@ add_digit :: proc(dest, a: ^Int, digit: DIGIT) -> (err: Error) {
 		If `a` is negative and `|a|` >= `digit`, call `dest = |a| - digit`
 	*/
 	if is_neg(a) && (a.used > 1 || a.digit[0] >= digit) {
-		fmt.print("a = neg, %v\n", print_int(a));
 		/*
 			Temporarily fix `a`'s sign.
 		*/

+ 15 - 16
core/math/bigint/bigint.odin

@@ -9,6 +9,8 @@ package bigint
 	The code started out as an idiomatic source port of libTomMath, which is in the public domain, with thanks.
 */
 
+import "core:intrinsics"
+
 /*
 	Tunables
 */
@@ -97,26 +99,23 @@ when size_of(rawptr) == 8 {
 	/*
 		We can use u128 as an intermediary.
 	*/
-	DIGIT       :: distinct(u64);
-	_DIGIT_BITS :: 60;
-	_WORD       :: u128;
-	_MAX_COMBA  :: 1 <<  (128 - (2 * _DIGIT_BITS))     ;
-	_WARRAY     :: 1 << ((128 - (2 * _DIGIT_BITS)) + 1);
+	DIGIT        :: distinct(u64);
+	_WORD        :: distinct(u128);
 } else {
-	DIGIT       :: distinct(u32);
-	_DIGIT_BITS :: 28;
-	_WORD       :: u64;
-	_MAX_COMBA  :: 1 <<  ( 64 - (2 * _DIGIT_BITS))     ;
-	_WARRAY     :: 1 << (( 64 - (2 * _DIGIT_BITS)) + 1);
+	DIGIT        :: distinct(u32);
+	_WORD        :: distinct(u64);
 }
 #assert(size_of(_WORD) == 2 * size_of(DIGIT));
-_MASK          :: (DIGIT(1) << DIGIT(_DIGIT_BITS)) - DIGIT(1);
-_DIGIT_MAX     :: _MASK;
 
-_BITS_IN_BYTE :: 8;
-_BITS_IN_TYPE :: #force_inline proc($T) -> int where intrinsics.type_is_integer(T) {
-	return _BITS_IN_BYTE * size_of(T);
-}
+_DIGIT_TYPE_BITS :: 8 * size_of(DIGIT);
+_WORD_TYPE_BITS  :: 8 * size_of(_WORD);
+
+_DIGIT_BITS      :: _DIGIT_TYPE_BITS - 4;
+
+_MASK            :: (DIGIT(1) << DIGIT(_DIGIT_BITS)) - DIGIT(1);
+_DIGIT_MAX       :: _MASK;
+_MAX_COMBA       :: 1 <<  (_WORD_TYPE_BITS - (2 * _DIGIT_BITS))     ;
+_WARRAY          :: 1 << ((_WORD_TYPE_BITS - (2 * _DIGIT_BITS)) + 1);
 
 Order :: enum i8 {
 	LSB_First = -1,

+ 3 - 3
core/math/bigint/example.odin

@@ -75,9 +75,9 @@ demo :: proc() {
 	err = sub(c, a, b);
 	// err = add(c, a, b);
 	fmt.printf("Error: %v\n", err);
-	fmt.printf("a: %v\n", print_int(a));
-	fmt.printf("b: %v\n", print_int(b));
-	fmt.printf("c: %v\n", print_int(c));
+	fmt.printf("a: %v, bits: %v\n", print_int(a), count_bits(a));
+	fmt.printf("b: %v, bits: %v\n", print_int(b), count_bits(b));
+	fmt.printf("c: %v, bits: %v\n", print_int(c), count_bits(c));
 }
 
 main :: proc() {

+ 23 - 0
core/math/bigint/helpers.odin

@@ -217,6 +217,29 @@ minus_one :: proc(a: ^Int, minimize := false) -> (err: Error) {
 	return .OK;
 }
 
+/*
+	Count bits in an `Int`.
+*/
+count_bits :: proc(a: ^Int) -> (count: int) {
+	assert_initialized(a);
+	/*
+		Fast path for zero.
+	*/
+	if is_zero(a) {
+		return 0;
+	}
+	/*
+		Get the number of DIGITs and use it.
+	*/
+	count  = (a.used - 1) * _DIGIT_BITS;
+	/*
+		Take the last DIGIT and count the bits in it.
+	*/
+	clz   := int(intrinsics.count_leading_zeros(a.digit[a.used - 1]));
+	count += (_DIGIT_TYPE_BITS - clz);
+	return;
+}
+
 /*
 	Internal helpers.
 */