Files
owniverse/world/owniverse/math/big_integer.gd
T
Kirill fad862d618 Add benchmark for saved state performance
- Introduced `benchmark_saved_state.gd` to evaluate the performance of the saved state restoration process.
- Implemented JSON integer restoration to handle large integers accurately.
- Added command-line argument parsing for specifying the path to the diagnostic JSON file and optional delta seconds.
- Conducted performance tests at different speeds and logged the elapsed time for six consecutive steps.
- Created a new UID file for the benchmark script.
2026-09-30 22:46:26 +03:00

105 lines
3.8 KiB
GDScript

extends RefCounted
## Unsigned little-endian base 10^9 arithmetic. Inputs are never mutated.
const BASE: int = 1000000000
static func trim(a: Array) -> Array:
while a.size() > 1 and a.back() == 0: a.pop_back()
return a
static func parse(text: String) -> Array:
var result: Array = []
var end: int = text.length()
while end > 0:
var start: int = maxi(0, end - 9)
result.append(int(text.substr(start, end - start)))
end = start
return trim(result if not result.is_empty() else [0])
static func decimal(a: Array) -> String:
var result: String = str(a.back())
for i in range(a.size() - 2, -1, -1): result += "%09d" % a[i]
return result
static func compare(a: Array, b: Array) -> int:
if a.size() != b.size(): return 1 if a.size() > b.size() else -1
for i in range(a.size() - 1, -1, -1):
if a[i] != b[i]: return 1 if a[i] > b[i] else -1
return 0
static func add(a: Array, b: Array) -> Array:
var result: Array = []
var carry: int = 0
for i in maxi(a.size(), b.size()):
var value: int = carry + (a[i] if i < a.size() else 0) + (b[i] if i < b.size() else 0)
result.append(value % BASE)
carry = value / BASE
if carry: result.append(carry)
return result
static func subtract(a: Array, b: Array) -> Array:
assert(compare(a, b) >= 0, "Unsigned subtraction underflow")
var result: Array = []
var borrow: int = 0
for i in a.size():
var value: int = a[i] - borrow - (b[i] if i < b.size() else 0)
borrow = 1 if value < 0 else 0
result.append(value + BASE if borrow else value)
return trim(result)
static func multiply(a: Array, b: Array) -> Array:
var result: Array = []
result.resize(a.size() + b.size())
result.fill(0)
for i in a.size():
var carry: int = 0
for j in b.size():
# < BASE^2 + 2*BASE: comfortably inside signed int64.
var value: int = a[i] * b[j] + result[i + j] + carry
result[i + j] = value % BASE
carry = value / BASE
result[i + b.size()] = carry
return trim(result)
static func divmod(a: Array, b: Array) -> Array:
assert(b != [0], "Division by zero")
if b == [1]: return [a.duplicate(), [0]]
if compare(a, b) < 0: return [[0], a.duplicate()]
if b.size() == 1:
var quotient: Array = []
quotient.resize(a.size())
var carry: int = 0
for i in range(a.size() - 1, -1, -1):
var value: int = carry * BASE + a[i]
quotient[i] = value / b[0]
carry = value % b[0]
return [trim(quotient), [carry]]
# Normalize the leading divisor limb so the two-limb quotient estimate
# needs at most two downward corrections (Knuth's division estimate).
var factor: int = BASE / (b.back() + 1)
a = multiply(a, [factor])
b = multiply(b, [factor])
var quotient: Array = []
quotient.resize(a.size())
var remainder: Array = [0]
for i in range(a.size() - 1, -1, -1):
remainder.push_front(a[i])
trim(remainder)
var high: int = remainder[b.size()] if remainder.size() > b.size() else 0
var low: int = remainder[b.size() - 1] if remainder.size() >= b.size() else 0
var estimate: int = mini(BASE - 1, (high * BASE + low) / b.back())
var product: Array = multiply(b, [estimate])
while compare(product, remainder) > 0:
estimate -= 1
product = subtract(product, b)
quotient[i] = estimate
remainder = subtract(remainder, product)
return [trim(quotient), divmod(remainder, [factor])[0]]
static func gcd(a: Array, b: Array) -> Array:
while b != [0]:
if b == [1]: return [1]
var remainder: Array = divmod(a, b)[1]
a = b
b = remainder
return a