瀏覽代碼

Fix `strconv.parse_float` related procedures caused by a shifting problem

gingerBill 4 月之前
父節點
當前提交
4ec03a2d9b
共有 2 個文件被更改,包括 24 次插入34 次删除
  1. 1 2
      core/strconv/decimal/decimal.odin
  2. 23 32
      core/strconv/generic_float.odin

+ 1 - 2
core/strconv/decimal/decimal.odin

@@ -399,7 +399,7 @@ shift_left :: proc(a: ^Decimal, k: uint) #no_bounds_check {
 
 
 	a.decimal_point += delta
 	a.decimal_point += delta
 
 
-	a.count = clamp(a.count, 0, len(a.digits))
+	a.count = clamp(a.count+delta, 0, len(a.digits))
 	trim(a)
 	trim(a)
 }
 }
 /*
 /*
@@ -562,4 +562,3 @@ rounded_integer :: proc(a: ^Decimal) -> u64 {
 	}
 	}
 	return n
 	return n
 }
 }
-

+ 23 - 32
core/strconv/generic_float.odin

@@ -339,45 +339,37 @@ Converts a decimal number to its floating-point representation with the given fo
 - b: The bits representing the floating-point number
 - b: The bits representing the floating-point number
 - overflow: A boolean indicating whether an overflow occurred during conversion
 - overflow: A boolean indicating whether an overflow occurred during conversion
 */
 */
-@(private)
 decimal_to_float_bits :: proc(d: ^decimal.Decimal, info: ^Float_Info) -> (b: u64, overflow: bool) {
 decimal_to_float_bits :: proc(d: ^decimal.Decimal, info: ^Float_Info) -> (b: u64, overflow: bool) {
-	end :: proc "contextless" (d: ^decimal.Decimal, mant: u64, exp: int, info: ^Float_Info) -> (bits: u64) {
+	overflow_end :: proc "contextless" (d: ^decimal.Decimal, info: ^Float_Info) -> (u64, bool) {
+		mant: u64 = 0
+		exp:  int = 1<<info.expbits - 1 + info.bias
+		return end(d, mant, exp, info, true)
+	}
+	end :: proc "contextless" (d: ^decimal.Decimal, mant: u64, exp: int, info: ^Float_Info, is_overflow: bool) -> (bits: u64, overflow: bool) {
 		bits = mant & (u64(1)<<info.mantbits - 1)
 		bits = mant & (u64(1)<<info.mantbits - 1)
 		bits |= u64((exp-info.bias) & (1<<info.expbits - 1)) << info.mantbits
 		bits |= u64((exp-info.bias) & (1<<info.expbits - 1)) << info.mantbits
 		if d.neg {
 		if d.neg {
-			bits |= 1<< info.mantbits << info.expbits
+			bits |= 1 << info.mantbits << info.expbits
 		}
 		}
+		overflow = is_overflow
 		return
 		return
 	}
 	}
-	set_overflow :: proc "contextless" (mant: ^u64, exp: ^int, info: ^Float_Info) -> bool {
-		mant^ = 0
-		exp^ = 1<<info.expbits - 1 + info.bias
-		return true
-	}
 
 
-	mant: u64
-	exp: int
 	if d.count == 0 {
 	if d.count == 0 {
-		mant = 0
-		exp = info.bias
-		b = end(d, mant, exp, info)
-		return
+		return end(d, 0, info.bias, info, false)
 	}
 	}
 
 
+
 	if d.decimal_point > 310 {
 	if d.decimal_point > 310 {
-		set_overflow(&mant, &exp, info)
-		b = end(d, mant, exp, info)
-		return
+		return overflow_end(d, info)
 	} else if d.decimal_point < -330 {
 	} else if d.decimal_point < -330 {
-		mant = 0
-		exp = info.bias
-		b = end(d, mant, exp, info)
-		return
+		return end(d, 0, info.bias, info, false)
 	}
 	}
 
 
 	@(static, rodata) power_table := [?]int{1, 3, 6, 9, 13, 16, 19, 23, 26}
 	@(static, rodata) power_table := [?]int{1, 3, 6, 9, 13, 16, 19, 23, 26}
 
 
-	exp = 0
+
+	exp := 0
 	for d.decimal_point > 0 {
 	for d.decimal_point > 0 {
 		n := 27 if d.decimal_point >= len(power_table) else power_table[d.decimal_point]
 		n := 27 if d.decimal_point >= len(power_table) else power_table[d.decimal_point]
 		decimal.shift(d, -n)
 		decimal.shift(d, -n)
@@ -392,35 +384,34 @@ decimal_to_float_bits :: proc(d: ^decimal.Decimal, info: ^Float_Info) -> (b: u64
 	// go from [0.5, 1) to [1, 2)
 	// go from [0.5, 1) to [1, 2)
 	exp -= 1
 	exp -= 1
 
 
+	// Min rep exp is 1+bias
 	if exp < info.bias + 1 {
 	if exp < info.bias + 1 {
 		n := info.bias + 1 - exp
 		n := info.bias + 1 - exp
-		decimal.shift(d, n)
+		decimal.shift(d, -n)
 		exp += n
 		exp += n
 	}
 	}
 
 
 	if (exp-info.bias) >= (1<<info.expbits - 1) {
 	if (exp-info.bias) >= (1<<info.expbits - 1) {
-		set_overflow(&mant, &exp, info)
-		b = end(d, mant, exp, info)
-		return
+		return overflow_end(d, info)
 	}
 	}
 
 
+	// Extract 1 + mantbits
 	decimal.shift(d, int(1 + info.mantbits))
 	decimal.shift(d, int(1 + info.mantbits))
-	mant = decimal.rounded_integer(d)
+	mant := decimal.rounded_integer(d)
 
 
+	// Rounding for shift down
 	if mant == 2<<info.mantbits {
 	if mant == 2<<info.mantbits {
 		mant >>= 1
 		mant >>= 1
 		exp += 1
 		exp += 1
 		if (exp-info.bias) >= (1<<info.expbits - 1) {
 		if (exp-info.bias) >= (1<<info.expbits - 1) {
-			set_overflow(&mant, &exp, info)
-			b = end(d, mant, exp, info)
-			return
+			return overflow_end(d, info)
 		}
 		}
 	}
 	}
 
 
+	// Check for denormalized mantissa
 	if mant & (1<<info.mantbits) == 0 {
 	if mant & (1<<info.mantbits) == 0 {
 		exp = info.bias
 		exp = info.bias
 	}
 	}
 
 
-	b = end(d, mant, exp, info)
-	return
+	return end(d, mant, exp, info, false)
 }
 }