Преглед изворни кода

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 `a` is negative and `|a|` >= `digit`, call `dest = |a| - digit`
 	*/
 	*/
 	if is_neg(a) && (a.used > 1 || a.digit[0] >= 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.
 			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.
 	The code started out as an idiomatic source port of libTomMath, which is in the public domain, with thanks.
 */
 */
 
 
+import "core:intrinsics"
+
 /*
 /*
 	Tunables
 	Tunables
 */
 */
@@ -97,26 +99,23 @@ when size_of(rawptr) == 8 {
 	/*
 	/*
 		We can use u128 as an intermediary.
 		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 {
 } 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));
 #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 {
 Order :: enum i8 {
 	LSB_First = -1,
 	LSB_First = -1,

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

@@ -75,9 +75,9 @@ demo :: proc() {
 	err = sub(c, a, b);
 	err = sub(c, a, b);
 	// err = add(c, a, b);
 	// err = add(c, a, b);
 	fmt.printf("Error: %v\n", err);
 	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() {
 main :: proc() {

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

@@ -217,6 +217,29 @@ minus_one :: proc(a: ^Int, minimize := false) -> (err: Error) {
 	return .OK;
 	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.
 	Internal helpers.
 */
 */