fad862d618
- 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.
105 lines
3.8 KiB
GDScript
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
|