浏览代码

big: Improve `int_to_bytes_*`.

Jeroen van Rijn 4 年之前
父节点
当前提交
ee24f2dd37
共有 2 个文件被更改,包括 161 次插入87 次删除
  1. 94 46
      core/math/big/example.odin
  2. 67 41
      core/math/big/helpers.odin

+ 94 - 46
core/math/big/example.odin

@@ -73,67 +73,115 @@ print :: proc(name: string, a: ^Int, base := i8(10), print_name := true, newline
 	}
 }
 
-demo :: proc() {
-	a, b, c, d, e, f := &Int{}, &Int{}, &Int{}, &Int{}, &Int{}, &Int{};
-	defer destroy(a, b, c, d, e, f);
-
+int_to_byte :: proc(v: ^Int) {
 	err: Error;
+	size: int;
+	print("v: ", v);
+	fmt.println();
 
-	foo := "2291194942392555914538479778530519876003906024854260006581638127590953";
-	if err = atoi(a, foo, 10); err != nil { return; }
-	// print("a: ", a, 10, true, true, true);
-
-	byte_length, _ := int_to_bytes_size(a);
-
-	fmt.printf("byte_length(a): %v\n", byte_length);
+	if size, err = int_to_bytes_size(v); err != nil {
+		fmt.printf("int_to_bytes_size returned: %v\n", err);
+		return;
+	}
+	b1 := make([]u8, size, context.temp_allocator);
+	err = int_to_bytes_big(v, b1);
+	fmt.printf("big: %v | err: %v\n", b1, err);
 
-	buf := make([]u8, byte_length);
-	defer delete(buf);
 
-	err = int_to_bytes_big(a, buf);
+	if size, err = int_to_bytes_size(v); err != nil {
+		fmt.printf("int_to_bytes_size returned: %v\n", err);
+		return;
+	}
+	b2 := make([]u8, size, context.temp_allocator);
+	err = int_to_bytes_big_python(v, b2);
+	fmt.printf("big python: %v | err: %v\n", b2, err);
 
-	python_big := []u8{
-		 84, 252,  50,  97,  27,  81,  11, 101,  58,  96, 138, 175,  65, 202, 109,
-		142, 106, 146, 117,  32, 200, 113,  36, 214, 188, 157, 242, 158,  41,
-	};
 
-	if mem.compare(python_big, buf) == 0 {
-		fmt.printf("int_to_bytes_big: pass\n");
-	} else {
-		fmt.printf("int_to_bytes_big: fail | %v\n", buf);
+	if size, err = int_to_bytes_size(v, true); err != nil {
+		fmt.printf("int_to_bytes_size returned: %v\n", err);
+		return;
 	}
-	python_little := []u8{
-		 41, 158, 242, 157, 188, 214,  36, 113, 200,  32, 117, 146, 106, 142, 109,
-		202,  65, 175, 138,  96,  58, 101,  11,  81,  27,  97,  50, 252,  84,
-	};
-
-	err = int_to_bytes_little(a, buf);
-	if mem.compare(python_little, buf) == 0 {
-		fmt.printf("int_to_bytes_little: pass\n");
-	} else {
-		fmt.printf("int_to_bytes_little: fail | %v\n", buf);
+	b3 := make([]u8, size, context.temp_allocator);
+	err = int_to_bytes_big(v, b3, true);
+	fmt.printf("big signed: %v | err: %v\n", b3, err);
+
+	t := &Int{};
+	int_from_bytes_big(t, b3, true);
+	defer destroy(t);
+	print("t: ", t);
+
+	if size, err = int_to_bytes_size(v, true); err != nil {
+		fmt.printf("int_to_bytes_size returned: %v\n", err);
+		return;
 	}
+	b4 := make([]u8, size, context.temp_allocator);
+	err = int_to_bytes_big_python(v, b4, true);
+	fmt.printf("big signed python: %v | err: %v\n", b4, err);
+}
 
-	_ = neg(b, a);
+int_to_byte_little :: proc(v: ^Int) {
+	err: Error;
+	size: int;
+	print("v: ", v);
+	fmt.println();
 
-	python_little_neg := []u8{
-		215,  97,  13,  98,  67,  41, 219, 142,  55, 223, 138, 109, 149, 113, 146,
-		 53, 190,  80, 117, 159, 197, 154, 244, 174, 228, 158, 205,   3, 171,
-	};
+	if size, err = int_to_bytes_size(v); err != nil {
+		fmt.printf("int_to_bytes_size returned: %v\n", err);
+		return;
+	}
+	b1 := make([]u8, size, context.temp_allocator);
+	err = int_to_bytes_little(v, b1);
+	fmt.printf("little: %v | err: %v\n", b1, err);
 
-	byte_length, _ = int_to_bytes_size_python(b, true);
 
-	fmt.printf("byte_length(a): %v\n", byte_length);
+	if size, err = int_to_bytes_size(v); err != nil {
+		fmt.printf("int_to_bytes_size returned: %v\n", err);
+		return;
+	}
+	b2 := make([]u8, size, context.temp_allocator);
+	err = int_to_bytes_little_python(v, b2);
+	fmt.printf("little python: %v | err: %v\n", b2, err);
 
-	buf2 := make([]u8, byte_length);
-	defer delete(buf2);
 
-	err = int_to_bytes_little_python(b, buf, true);
-	if mem.compare(python_little_neg, buf) == 0 {
-		fmt.printf("int_to_bytes_little: pass\n");
-	} else {
-		fmt.printf("int_to_bytes_little: %v | %v\n", err, buf);
+	if size, err = int_to_bytes_size(v, true); err != nil {
+		fmt.printf("int_to_bytes_size returned: %v\n", err);
+		return;
+	}
+	b3 := make([]u8, size, context.temp_allocator);
+	err = int_to_bytes_little(v, b3, true);
+	fmt.printf("little signed: %v | err: %v\n", b3, err);
+
+	// t := &Int{};
+	// int_from_bytes_little(t, b3, true);
+	// defer destroy(t);
+	// print("t: ", t);
+
+	if size, err = int_to_bytes_size(v, true); err != nil {
+		fmt.printf("int_to_bytes_size returned: %v\n", err);
+		return;
 	}
+	b4 := make([]u8, size, context.temp_allocator);
+	err = int_to_bytes_little_python(v, b4, true);
+	fmt.printf("little signed python: %v | err: %v\n", b4, err);
+}
+
+demo :: proc() {
+	a, b, c, d, e, f := &Int{}, &Int{}, &Int{}, &Int{}, &Int{}, &Int{};
+	defer destroy(a, b, c, d, e, f);
+
+	set(a, 64336);
+	fmt.println("--- --- --- ---");
+	int_to_byte(a);
+	fmt.println("--- --- --- ---");
+	int_to_byte_little(a);
+	fmt.println("--- --- --- ---");
+
+	set(b, -64336);
+	fmt.println("--- --- --- ---");
+	int_to_byte(b);
+	fmt.println("--- --- --- ---");
+	int_to_byte_little(b);
+	fmt.println("--- --- --- ---");
 }
 
 main :: proc() {

+ 67 - 41
core/math/big/helpers.odin

@@ -480,22 +480,6 @@ int_to_bytes_size :: proc(a: ^Int, signed := false, allocator := context.allocat
 	return;
 }
 
-/*
-	Size binary representation, Python `._to_bytes(num_bytes, "endianness", signed=Bool)` compatible.
-*/
-int_to_bytes_size_python :: proc(a: ^Int, signed := false, allocator := context.allocator) -> (size_in_bytes: int, err: Error) {
-	assert_if_nil(a);
-	size_in_bytes, err = int_to_bytes_size(a, signed, allocator);
-
-	/*
-		Python uses a complement representation of negative numbers and doesn't add a prefix byte.
-	*/
-	if signed {
-		size_in_bytes -= 1;
-	}
-	return;
-}
-
 /*
 	Return Little Endian binary representation of `a`, either signed or unsigned.
 	If `a` is negative and we ask for the default unsigned representation, we return abs(a).
@@ -505,13 +489,13 @@ int_to_bytes_little :: proc(a: ^Int, buf: []u8, signed := false, allocator := co
 	size_in_bytes: int;
 
 	if size_in_bytes, err = int_to_bytes_size(a, signed, allocator); err != nil { return err; }
-	if size_in_bytes > len(buf) { return .Buffer_Overflow; }
+	l := len(buf);
+	if size_in_bytes > l { return .Buffer_Overflow; }
 
 	size_in_bits := internal_count_bits(a);
 	i := 0;
 	if signed {
-		i += 1;
-		buf[0] = 1 if a.sign == .Negative else 0;
+		buf[l - 1] = 1 if a.sign == .Negative else 0;
 	}
 	for offset := 0; offset < size_in_bits; offset += 8 {
 		bits, _ := internal_int_bitfield_extract(a, offset, 8);
@@ -553,24 +537,31 @@ int_to_bytes_little_python :: proc(a: ^Int, buf: []u8, signed := false, allocato
 	assert_if_nil(a);
 	size_in_bytes: int;
 
-	if a.sign == .Zero_or_Positive {
-		return int_to_bytes_little(a, buf, signed, allocator);
-	}
-	if a.sign == .Negative && !signed { return .Invalid_Argument; }
+	if !signed && a.sign == .Negative { return .Invalid_Argument; }
 
 	l := len(buf);
-	if size_in_bytes, err = int_to_bytes_size_python(a, signed, allocator); err != nil { return err; }
+	if size_in_bytes, err = int_to_bytes_size(a, signed, allocator); err != nil { return err; }
 	if size_in_bytes > l              { return .Buffer_Overflow;  }
 
-	t := &Int{};
-	defer destroy(t);
-	if err = complement(t, a, allocator); err != nil { return err; }
-
-	size_in_bits := internal_count_bits(t);
-	i := 0;
-	for offset := 0; offset < size_in_bits; offset += 8 {
-		bits, _ := internal_int_bitfield_extract(t, offset, 8);
-		buf[i] = 255 - u8(bits & 255); i += 1;
+	if a.sign == .Negative {
+		t := &Int{};
+		defer destroy(t);
+		if err = internal_complement(t, a, allocator); err != nil { return err; }
+
+		size_in_bits := internal_count_bits(t);
+		i := 0;
+		for offset := 0; offset < size_in_bits; offset += 8 {
+			bits, _ := internal_int_bitfield_extract(t, offset, 8);
+			buf[i] = 255 - u8(bits & 255); i += 1;
+		}
+		buf[l-1] = 255;
+	} else {
+		size_in_bits := internal_count_bits(a);
+		i := 0;
+		for offset := 0; offset < size_in_bits; offset += 8 {
+			bits, _ := internal_int_bitfield_extract(a, offset, 8);
+			buf[i] = u8(bits & 255); i += 1;
+		}
 	}
 	return;
 }
@@ -583,29 +574,64 @@ int_to_bytes_big_python :: proc(a: ^Int, buf: []u8, signed := false, allocator :
 	assert_if_nil(a);
 	size_in_bytes: int;
 
-	if a.sign == .Zero_or_Positive {
-		return int_to_bytes_big(a, buf, signed, allocator);
-	}
-	if a.sign == .Negative && !signed { return .Invalid_Argument; }
+	if !signed && a.sign == .Negative { return .Invalid_Argument; }
+	if a.sign == .Zero_or_Positive    { return int_to_bytes_big(a, buf, signed, allocator); }
 
 	l := len(buf);
-	if size_in_bytes, err = int_to_bytes_size_python(a, signed, allocator); err != nil { return err; }
+	if size_in_bytes, err = int_to_bytes_size(a, signed, allocator); err != nil { return err; }
 	if size_in_bytes > l              { return .Buffer_Overflow;  }
 
 	t := &Int{};
 	defer destroy(t);
-	if err = complement(t, a, allocator); err != nil { return err; }
+
+	if err = internal_complement(t, a, allocator); err != nil { return err; }
 
 	size_in_bits := internal_count_bits(t);
 	i := l - 1;
-
 	for offset := 0; offset < size_in_bits; offset += 8 {
-		bits, _ := internal_int_bitfield_extract(a, offset, 8);
+		bits, _ := internal_int_bitfield_extract(t, offset, 8);
 		buf[i] = 255 - u8(bits & 255); i -= 1;
 	}
+	buf[0] = 255;
+
 	return;
 }
 
+/*
+	Read `Int` from a Big Endian binary representation.
+	Sign is detected from the first byte if `signed` is true.
+*/
+int_from_bytes_big :: proc(a: ^Int, buf: []u8, signed := false, allocator := context.allocator) -> (err: Error) {
+	assert_if_nil(a);
+	buf := buf;
+	l := len(buf);
+	if l == 0 { return .Invalid_Argument; }
+
+	sign: Sign;
+	size_in_bits   := l * 8;
+	if signed { 
+		/*
+			First byte denotes the sign.
+		*/
+		size_in_bits -= 8;
+	}
+	size_in_digits := size_in_bits / _DIGIT_BITS;
+	size_in_digits += 0 if size_in_bits % 8 == 0 else 1;
+	if err = internal_grow(a, size_in_digits); err != nil { return err; }
+
+	if signed {
+		sign = .Zero_or_Positive if buf[0] == 0 else .Negative;
+		buf = buf[1:];
+	}
+
+	for v in buf {
+		if err = internal_shl(a, a, 8); err != nil { return err; }
+		a.digit[0] |= DIGIT(v);
+	}
+	a.sign = sign;
+	return internal_clamp(a);
+}
+
 /*
 	Initialize constants.
 */