summaryrefslogtreecommitdiff
path: root/libs/Big.gd
diff options
context:
space:
mode:
authorjacob janzen <53062115+JacobJanzen@users.noreply.github.com>2024-11-16 11:43:41 -0600
committerGitHub <noreply@github.com>2024-11-16 11:43:41 -0600
commit1a6dd05f13d7afb312332c9636436cadcf01639b (patch)
treeacf15e3a8d0765e743661a0aec78b6c4da64c829 /libs/Big.gd
parentdf074ff75646f543b634d229c3e183a991403890 (diff)
Stonks for real this time (#2)
* start labels * stonks * stonks for real this time
Diffstat (limited to 'libs/Big.gd')
-rw-r--r--libs/Big.gd902
1 files changed, 902 insertions, 0 deletions
diff --git a/libs/Big.gd b/libs/Big.gd
new file mode 100644
index 0000000..747bae3
--- /dev/null
+++ b/libs/Big.gd
@@ -0,0 +1,902 @@
+class_name Big
+extends RefCounted
+## Big number class for use in idle / incremental games and other games that needs very large numbers
+##
+## Can format large numbers using a variety of notation methods:[br]
+## AA notation like AA, AB, AC etc.[br]
+## Metric symbol notation k, m, G, T etc.[br]
+## Metric name notation kilo, mega, giga, tera etc.[br]
+## Long names like octo-vigin-tillion or millia-nongen-quin-vigin-tillion (based on work by Landon Curt Noll)[br]
+## Scientic notation like 13e37 or 42e42[br]
+## Long strings like 4200000000 or 13370000000000000000000000000000[br][br]
+## Please note that this class has limited precision and does not fully support negative exponents[br]
+
+## Big Number Mantissa
+var mantissa: float
+## Big Number Exponent
+var exponent: int
+
+## Metric Symbol Suffixes
+const suffixes_metric_symbol: Dictionary = {
+ "0": "",
+ "1": "k",
+ "2": "M",
+ "3": "G",
+ "4": "T",
+ "5": "P",
+ "6": "E",
+ "7": "Z",
+ "8": "Y",
+ "9": "R",
+ "10": "Q",
+}
+## Metric Name Suffixes
+const suffixes_metric_name: Dictionary = {
+ "0": "",
+ "1": "kilo",
+ "2": "mega",
+ "3": "giga",
+ "4": "tera",
+ "5": "peta",
+ "6": "exa",
+ "7": "zetta",
+ "8": "yotta",
+ "9": "ronna",
+ "10": "quetta",
+}
+
+# HACK: This dictionary is inefficient, along with toAA().
+# Replace with better, ideally utilizing alphabet_aa system
+## AA Suffixes
+## @deprecated
+static var suffixes_aa: Dictionary = {
+ "0": "",
+ "1": "k",
+ "2": "m",
+ "3": "b",
+ "4": "t",
+ "5": "aa",
+ "6": "ab",
+ "7": "ac",
+ "8": "ad",
+ "9": "ae",
+ "10": "af",
+ "11": "ag",
+ "12": "ah",
+ "13": "ai",
+ "14": "aj",
+ "15": "ak",
+ "16": "al",
+ "17": "am",
+ "18": "an",
+ "19": "ao",
+ "20": "ap",
+ "21": "aq",
+ "22": "ar",
+ "23": "as",
+ "24": "at",
+ "25": "au",
+ "26": "av",
+ "27": "aw",
+ "28": "ax",
+ "29": "ay",
+ "30": "az",
+ "31": "ba",
+ "32": "bb",
+ "33": "bc",
+ "34": "bd",
+ "35": "be",
+ "36": "bf",
+ "37": "bg",
+ "38": "bh",
+ "39": "bi",
+ "40": "bj",
+ "41": "bk",
+ "42": "bl",
+ "43": "bm",
+ "44": "bn",
+ "45": "bo",
+ "46": "bp",
+ "47": "bq",
+ "48": "br",
+ "49": "bs",
+ "50": "bt",
+ "51": "bu",
+ "52": "bv",
+ "53": "bw",
+ "54": "bx",
+ "55": "by",
+ "56": "bz",
+ "57": "ca"
+}
+
+## AA Alphabet
+const alphabet_aa: Array[String] = [
+ "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m",
+ "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z"
+]
+
+## Latin Ones Prefixes
+const latin_ones: Array[String] = [
+ "", "un", "duo", "tre", "quattuor", "quin", "sex", "septen", "octo", "novem"
+]
+## Latin Tens Prefixes
+const latin_tens: Array[String] = [
+ "", "dec", "vigin", "trigin", "quadragin", "quinquagin", "sexagin", "septuagin", "octogin", "nonagin"
+]
+## Latin Hundreds Prefixes
+const latin_hundreds: Array[String] = [
+ "", "cen", "duocen", "trecen", "quadringen", "quingen", "sescen", "septingen", "octingen", "nongen"
+]
+## Latin Special Prefixes
+const latin_special: Array[String] = [
+ "", "mi", "bi", "tri", "quadri", "quin", "sex", "sept", "oct", "non"
+]
+
+## Various options to control the string presentation of Big Numbers
+static var options = {
+ "dynamic_decimals": false,
+ "dynamic_numbers": 4,
+ "small_decimals": 3,
+ "thousand_decimals": 1,
+ "big_decimals": 1,
+ "scientific_decimals": 3,
+ "logarithmic_decimals": 4,
+ "thousand_separator": ",",
+ "decimal_separator": ".",
+ "suffix_separator": "",
+ "reading_separator": "",
+ "thousand_name": "thousand"
+}
+
+## Maximum Big Number Mantissa
+const MANTISSA_MAX: float = 1209600.0
+## Big Number Mantissa floating-point precision
+const MANTISSA_PRECISION: float = 0.0000001
+
+## int (signed 64-bit) minimum value
+const INT_MIN: int = -9223372036854775808
+## int (signed 64-bit) maximum value
+const INT_MAX: int = 9223372036854775807
+
+func _init(m: Variant = 1.0, e: int = 0) -> void:
+ if m is Big:
+ mantissa = m.mantissa
+ exponent = m.exponent
+ elif typeof(m) == TYPE_STRING:
+ var scientific: PackedStringArray = m.split("e")
+ mantissa = float(scientific[0])
+ exponent = int(scientific[1]) if scientific.size() > 1 else 0
+ else:
+ if typeof(m) != TYPE_INT and typeof(m) != TYPE_FLOAT:
+ printerr("Big Error: Unknown data type passed as a mantissa!")
+ mantissa = m
+ exponent = e
+ Big._sizeCheck(mantissa)
+ Big.normalize(self)
+
+## Verifies (or converts) an argument into a Big number
+static func _typeCheck(n) -> Big:
+ if n is Big:
+ return n
+ var result := Big.new(n)
+ return result
+
+## Warns if Big number's mantissa exceeds max
+static func _sizeCheck(m: float) -> void:
+ if m > MANTISSA_MAX:
+ printerr("Big Error: Mantissa \"" + str(m) + "\" exceeds MANTISSA_MAX. Use exponent or scientific notation")
+
+
+## [url=https://en.wikipedia.org/wiki/Normalized_number]Normalize[/url] a Big number
+static func normalize(big: Big) -> void:
+ # Store sign if negative
+ var is_negative := false
+ if big.mantissa < 0:
+ is_negative = true
+ big.mantissa *= -1
+
+ if big.mantissa < 1.0 or big.mantissa >= 10.0:
+ var diff: int = floor(log10(big.mantissa))
+ if diff > -10 and diff < 248:
+ var div = 10.0 ** diff
+ if div > MANTISSA_PRECISION:
+ big.mantissa /= div
+ big.exponent += diff
+ while big.exponent < 0:
+ big.mantissa *= 0.1
+ big.exponent += 1
+ while big.mantissa >= 10.0:
+ big.mantissa *= 0.1
+ big.exponent += 1
+ if big.mantissa == 0:
+ big.mantissa = 0.0
+ big.exponent = 0
+ big.mantissa = snapped(big.mantissa, MANTISSA_PRECISION)
+
+ # Return sign if negative
+ if (is_negative):
+ big.mantissa *= -1
+
+
+## Returns the absolute value of a number in Big format
+static func absolute(x) -> Big:
+ var result := Big.new(x)
+ result.mantissa = abs(result.mantissa)
+ return result
+
+
+## Adds two numbers and returns the Big number result [br][br]
+static func add(x, y) -> Big:
+ x = Big._typeCheck(x)
+ y = Big._typeCheck(y)
+ var result := Big.new(x)
+
+ var exp_diff: float = y.exponent - x.exponent
+
+ if exp_diff < 248.0:
+ var scaled_mantissa: float = y.mantissa * 10 ** exp_diff
+ result.mantissa = x.mantissa + scaled_mantissa
+ elif x.isLessThan(y): # When difference between values is too big, discard the smaller number
+ result.mantissa = y.mantissa
+ result.exponent = y.exponent
+ Big.normalize(result)
+ return result
+
+
+## Subtracts two numbers and returns the Big number result
+static func subtract(x, y) -> Big:
+ var negated_y := Big.new(-y.mantissa, y.exponent)
+ return add(negated_y, x)
+
+
+## Multiplies two numbers and returns the Big number result
+static func multiply(x, y) -> Big:
+ x = Big._typeCheck(x)
+ y = Big._typeCheck(y)
+ var result := Big.new()
+
+ var new_exponent: int = y.exponent + x.exponent
+ var new_mantissa: float = y.mantissa * x.mantissa
+ while new_mantissa >= 10.0:
+ new_mantissa /= 10.0
+ new_exponent += 1
+ result.mantissa = new_mantissa
+ result.exponent = new_exponent
+ Big.normalize(result)
+ return result
+
+
+## Divides two numbers and returns the Big number result
+static func divide(x, y) -> Big:
+ x = Big._typeCheck(x)
+ y = Big._typeCheck(y)
+ var result := Big.new(x)
+
+ if y.mantissa > -MANTISSA_PRECISION and y.mantissa < MANTISSA_PRECISION:
+ printerr("Big Error: Divide by zero or less than " + str(MANTISSA_PRECISION))
+ return x
+ var new_exponent = x.exponent - y.exponent
+ var new_mantissa = x.mantissa / y.mantissa
+ while new_mantissa > 0.0 and new_mantissa < 1.0:
+ new_mantissa *= 10.0
+ new_exponent -= 1
+ result.mantissa = new_mantissa
+ result.exponent = new_exponent
+ Big.normalize(result)
+ return result
+
+
+## Raises a Big number to the nth power and returns the Big number result
+static func power(x: Big, y) -> Big:
+ var result := Big.new(x)
+ if typeof(y) == TYPE_INT:
+ if y <= 0:
+ if y < 0:
+ printerr("Big Error: Negative exponents are not supported!")
+ result.mantissa = 1.0
+ result.exponent = 0
+ return result
+
+ var y_mantissa: float = 1.0
+ var y_exponent: int = 0
+
+ while y > 1:
+ Big.normalize(result)
+ if y % 2 == 0:
+ result.exponent *= 2
+ result.mantissa **= 2
+ y = y / 2
+ else:
+ y_mantissa = result.mantissa * y_mantissa
+ y_exponent = result.exponent + y_exponent
+ result.exponent *= 2
+ result.mantissa **= 2
+ y = (y - 1) / 2
+
+ result.exponent = y_exponent + result.exponent
+ result.mantissa = y_mantissa * result.mantissa
+ Big.normalize(result)
+ return result
+ elif typeof(y) == TYPE_FLOAT:
+ if result.mantissa == 0:
+ return result
+
+ # fast track
+ var temp: float = result.exponent * y
+ var newMantissa = result.mantissa ** y
+ if (round(y) == y
+ and temp <= INT_MAX
+ and temp >= INT_MIN
+ and is_finite(temp)
+ ):
+ if is_finite(newMantissa):
+ result.mantissa = newMantissa
+ result.exponent = int(temp)
+ Big.normalize(result)
+ return result
+
+ # a bit slower, still supports floats
+ var newExponent: int = int(temp)
+ var residue: float = temp - newExponent
+ newMantissa = 10 ** (y * Big.log10(result.mantissa) + residue)
+ if newMantissa != INF and newMantissa != -INF:
+ result.mantissa = newMantissa
+ result.exponent = newExponent
+ Big.normalize(result)
+ return result
+
+ if round(y) != y:
+ printerr("Big Error: Power function does not support large floats, use integers!")
+
+ return power(x, int(y))
+ else:
+ printerr("Big Error: Unknown/unsupported data type passed as an exponent in power function!")
+ return x
+
+
+## Square Roots a given Big number and returns the Big number result
+static func root(x: Big) -> Big:
+ var result := Big.new(x)
+
+ if result.exponent % 2 == 0:
+ result.mantissa = sqrt(result.mantissa)
+ @warning_ignore("integer_division")
+ result.exponent = result.exponent / 2
+ else:
+ result.mantissa = sqrt(result.mantissa * 10)
+ @warning_ignore("integer_division")
+ result.exponent = (result.exponent - 1) / 2
+ Big.normalize(result)
+ return result
+
+
+## Modulos a number and returns the Big number result
+static func modulo(x, y) -> Big:
+ var result := Big.new(x.mantissa, x.exponent)
+ y = Big._typeCheck(y)
+ var big = { "mantissa": x.mantissa, "exponent": x.exponent }
+ Big.divide(result, y)
+ Big.roundDown(result)
+ Big.multiply(result, y)
+ Big.subtract(result, big)
+ result.mantissa = abs(result.mantissa)
+ return result
+
+
+## Rounds down a Big number
+static func roundDown(x: Big) -> Big:
+ if x.exponent == 0:
+ x.mantissa = floor(x.mantissa)
+ else:
+ var precision := 1.0
+ for i in range(min(8, x.exponent)):
+ precision /= 10.0
+ if precision < MANTISSA_PRECISION:
+ precision = MANTISSA_PRECISION
+ x.mantissa = floor(x.mantissa / precision) * precision
+ return x
+
+
+## Equivalent of [code]min(Big, Big)[/code]
+static func minValue(m, n) -> Big:
+ m = Big._typeCheck(m)
+ if m.isLessThan(n):
+ return m
+ else:
+ return n
+
+
+## Equivalent of [code]max(Big, Big)[/code]
+static func maxValue(m, n) -> Big:
+ m = Big._typeCheck(m)
+ if m.isGreaterThan(n):
+ return m
+ else:
+ return n
+
+
+## Equivalent of [code]Big + n[/code]
+func plus(n) -> Big:
+ return Big.add(self, n)
+
+
+## Equivalent of [code]Big += n[/code]
+func plusEquals(n) -> Big:
+ var new_value = Big.add(self, n)
+ mantissa = new_value.mantissa
+ exponent = new_value.exponent
+ return self
+
+## Equivalent of [code]Big - n[/code]
+func minus(n) -> Big:
+ return Big.subtract(self, n)
+
+
+## Equivalent of [code]Big -= n[/code]
+func minusEquals(n) -> Big:
+ var new_value: Big = Big.subtract(self, n)
+ mantissa = new_value.mantissa
+ exponent = new_value.exponent
+ return self
+
+
+## Equivalent of [code]Big * n[/code]
+func times(n) -> Big:
+ return Big.multiply(self, n)
+
+
+## Equivalent of [code]Big *= n[/code]
+func timesEquals(n) -> Big:
+ var new_value: Big = Big.multiply(self, n)
+ mantissa = new_value.mantissa
+ exponent = new_value.exponent
+ return self
+
+
+## Equivalent of [code]Big / n[/code]
+func dividedBy(n) -> Big:
+ return Big.divide(self, n)
+
+
+## Equivalent of [code]Big /= n[/code]
+func dividedByEquals(n) -> Big:
+ var new_value: Big = Big.divide(self, n)
+ mantissa = new_value.mantissa
+ exponent = new_value.exponent
+ return self
+
+
+## Equivalent of [code]Big % n[/code]
+func mod(n) -> Big:
+ return Big.modulo(self, n)
+
+
+## Equivalent of [code]Big %= n[/code]
+func modEquals(n) -> Big:
+ var new_value := Big.modulo(self, n)
+ mantissa = new_value.mantissa
+ exponent = new_value.exponent
+ return self
+
+
+## Equivalent of [code]Big ** n[/code]
+func toThePowerOf(n) -> Big:
+ return Big.power(self, n)
+
+
+## Equivalent of [code]Big **= n[/code]
+func toThePowerOfEquals(n) -> Big:
+ var new_value: Big = Big.power(self, n)
+ mantissa = new_value.mantissa
+ exponent = new_value.exponent
+ return self
+
+
+## Equivalent of [code]sqrt(Big)[/code]
+func squareRoot() -> Big:
+ var new_value := Big.root(self)
+ mantissa = new_value.mantissa
+ exponent = new_value.exponent
+ return self
+
+
+## Equivalent of [code]Big == n[/code]
+func isEqualTo(n) -> bool:
+ n = Big._typeCheck(n)
+ Big.normalize(n)
+ return n.exponent == exponent and is_equal_approx(n.mantissa, mantissa)
+
+
+## Equivalent of [code]Big > n[/code]
+func isGreaterThan(n) -> bool:
+ return !isLessThanOrEqualTo(n)
+
+
+## Equivalent of [code]Big >== n[/code]
+func isGreaterThanOrEqualTo(n) -> bool:
+ return !isLessThan(n)
+
+
+## Equivalent of [code]Big < n[/code]
+func isLessThan(n) -> bool:
+ n = Big._typeCheck(n)
+ Big.normalize(n)
+ if (mantissa == 0
+ and (n.mantissa > MANTISSA_PRECISION or mantissa < MANTISSA_PRECISION)
+ and n.mantissa == 0
+ ):
+ return false
+ if exponent < n.exponent:
+ if exponent == n.exponent - 1 and mantissa > 10*n.mantissa:
+ return false #9*10^3 > 0.1*10^4
+ return true
+ elif exponent == n.exponent:
+ if mantissa < n.mantissa:
+ return true
+ return false
+ else:
+ if exponent == n.exponent + 1 and mantissa * 10 < n.mantissa:
+ return true
+ return false
+
+
+## Equivalent of [code]Big <= n[/code]
+func isLessThanOrEqualTo(n) -> bool:
+ n = Big._typeCheck(n)
+ Big.normalize(n)
+ if isLessThan(n):
+ return true
+ if n.exponent == exponent and is_equal_approx(n.mantissa, mantissa):
+ return true
+ return false
+
+
+static func log10(x) -> float:
+ return log(x) * 0.4342944819032518
+
+
+func absLog10() -> float:
+ return exponent + Big.log10(abs(mantissa))
+
+
+func ln() -> float:
+ return 2.302585092994045 * logN(10)
+
+
+func logN(base) -> float:
+ return (2.302585092994046 / log(base)) * (exponent + Big.log10(mantissa))
+
+
+func pow10(value: int) -> void:
+ mantissa = 10 ** (value % 1)
+ exponent = int(value)
+
+
+## Sets the Thousand name option
+static func setThousandName(name: String) -> void:
+ options.thousand_name = name
+
+
+## Sets the Thousand Separator option
+static func setThousandSeparator(separator: String) -> void:
+ options.thousand_separator = separator
+
+
+## Sets the Decimal Separator option
+static func setDecimalSeparator(separator: String) -> void:
+ options.decimal_separator = separator
+
+
+## Sets the Suffix Separator option
+static func setSuffixSeparator(separator: String) -> void:
+ options.suffix_separator = separator
+
+
+## Sets the Reading Separator option
+static func setReadingSeparator(separator: String) -> void:
+ options.reading_separator = separator
+
+
+## Sets the Dynamic Decimals option
+static func setDynamicDecimals(d: bool) -> void:
+ options.dynamic_decimals = d
+
+
+## Sets the Dynamic numbers digits option
+static func setDynamicNumbers(d: int) -> void:
+ options.dynamic_numbers = d
+
+
+## Sets the small decimal digits option
+static func setSmallDecimals(d: int) -> void:
+ options.small_decimals = d
+
+
+## Sets the thousand decimal digits option
+static func setThousandDecimals(d: int) -> void:
+ options.thousand_decimals = d
+
+
+## Sets the big decimal digits option
+static func setBigDecimals(d: int) -> void:
+ options.big_decimals = d
+
+
+## Sets the scientific notation decimal digits option
+static func setScientificDecimals(d: int) -> void:
+ options.scientific_decimals = d
+
+
+## Sets the logarithmic notation decimal digits option
+static func setLogarithmicDecimals(d: int) -> void:
+ options.logarithmic_decimals = d
+
+
+## Converts the Big Number into a string
+func toString() -> String:
+ var mantissa_decimals := 0
+ if str(mantissa).find(".") >= 0:
+ mantissa_decimals = str(mantissa).split(".")[1].length()
+ if mantissa_decimals > exponent:
+ if exponent < 248:
+ return str(mantissa * 10 ** exponent)
+ else:
+ return toPlainScientific()
+ else:
+ var mantissa_string := str(mantissa).replace(".", "")
+ for _i in range(exponent-mantissa_decimals):
+ mantissa_string += "0"
+ return mantissa_string
+
+
+## Converts the Big Number into a string (in plain Scientific format)
+func toPlainScientific() -> String:
+ return str(mantissa) + "e" + str(exponent)
+
+
+## Converts the Big Number into a string (in Scientific format)
+func toScientific(no_decimals_on_small_values = false, force_decimals = false) -> String:
+ if exponent < 3:
+ var decimal_increments: float = 1 / (10 ** options.scientific_decimals / 10)
+ var value := str(snappedf(mantissa * 10 ** exponent, decimal_increments))
+ var split := value.split(".")
+ if no_decimals_on_small_values:
+ return split[0]
+ if split.size() > 1:
+ for i in range(options.logarithmic_decimals):
+ if split[1].length() < options.scientific_decimals:
+ split[1] += "0"
+ return split[0] + options.decimal_separator + split[1].substr(0,min(options.scientific_decimals, options.dynamic_numbers - split[0].length() if options.dynamic_decimals else options.scientific_decimals))
+ else:
+ return value
+ else:
+ var split := str(mantissa).split(".")
+ if split.size() == 1:
+ split.append("")
+ if force_decimals:
+ for i in range(options.scientific_decimals):
+ if split[1].length() < options.scientific_decimals:
+ split[1] += "0"
+ return split[0] + options.decimal_separator + split[1].substr(0,min(options.scientific_decimals, options.dynamic_numbers-1 - str(exponent).length() if options.dynamic_decimals else options.scientific_decimals)) + "e" + str(exponent)
+
+
+## Converts the Big Number into a string (in Logarithmic format)
+func toLogarithmic(no_decimals_on_small_values = false) -> String:
+ var decimal_increments: float = 1 / (10 ** options.logarithmic_decimals / 10)
+ if exponent < 3:
+ var value := str(snappedf(mantissa * 10 ** exponent, decimal_increments))
+ var split := value.split(".")
+ if no_decimals_on_small_values:
+ return split[0]
+ if split.size() > 1:
+ for i in range(options.logarithmic_decimals):
+ if split[1].length() < options.logarithmic_decimals:
+ split[1] += "0"
+ return split[0] + options.decimal_separator + split[1].substr(0,min(options.logarithmic_decimals, options.dynamic_numbers - split[0].length() if options.dynamic_decimals else options.logarithmic_decimals))
+ else:
+ return value
+ var dec := str(snappedf(abs(log(mantissa) / log(10) * 10), decimal_increments))
+ dec = dec.replace(".", "")
+ for i in range(options.logarithmic_decimals):
+ if dec.length() < options.logarithmic_decimals:
+ dec += "0"
+ var formated_exponent := formatExponent(exponent)
+ dec = dec.substr(0, min(options.logarithmic_decimals, options.dynamic_numbers - formated_exponent.length() if options.dynamic_decimals else options.logarithmic_decimals))
+ return "e" + formated_exponent + options.decimal_separator + dec
+
+
+## Formats an exponent for string format
+func formatExponent(value) -> String:
+ if value < 1000:
+ return str(value)
+ var string := str(value)
+ var string_mod := string.length() % 3
+ var output := ""
+ for i in range(0, string.length()):
+ if i != 0 and i % 3 == string_mod:
+ output += options.thousand_separator
+ output += string[i]
+ return output
+
+
+## Converts the Big Number into a float
+func toFloat() -> float:
+ return snappedf(float(str(mantissa) + "e" + str(exponent)),0.01)
+
+
+func toPrefix(no_decimals_on_small_values = false, use_thousand_symbol=true, force_decimals=true, scientic_prefix=false) -> String:
+ var number: float = mantissa
+ if not scientic_prefix:
+ var hundreds = 1
+ for _i in range(exponent % 3):
+ hundreds *= 10
+ number *= hundreds
+
+ var split := str(number).split(".")
+ if split.size() == 1:
+ split.append("")
+ if force_decimals:
+ var max_decimals = max(max(options.small_decimals, options.thousand_decimals), options.big_decimals)
+ for i in range(max_decimals):
+ if split[1].length() < max_decimals:
+ split[1] += "0"
+
+ if no_decimals_on_small_values and exponent < 3:
+ return split[0]
+ elif exponent < 3:
+ if options.small_decimals == 0 or split[1] == "":
+ return split[0]
+ else:
+ return split[0] + options.decimal_separator + split[1].substr(0,min(options.small_decimals, options.dynamic_numbers - split[0].length() if options.dynamic_decimals else options.small_decimals))
+ elif exponent < 6:
+ if options.thousand_decimals == 0 or (split[1] == "" and use_thousand_symbol):
+ return split[0]
+ else:
+ if use_thousand_symbol: # when the prefix is supposed to be using with a K for thousand
+ for i in range(3):
+ if split[1].length() < 3:
+ split[1] += "0"
+ return split[0] + options.decimal_separator + split[1].substr(0,min(3, options.dynamic_numbers - split[0].length() if options.dynamic_decimals else 3))
+ else:
+ for i in range(3):
+ if split[1].length() < 3:
+ split[1] += "0"
+ return split[0] + options.thousand_separator + split[1].substr(0,3)
+ else:
+ if options.big_decimals == 0 or split[1] == "":
+ return split[0]
+ else:
+ return split[0] + options.decimal_separator + split[1].substr(0,min(options.big_decimals, options.dynamic_numbers - split[0].length() if options.dynamic_decimals else options.big_decimals))
+
+
+func _latinPower(european_system) -> int:
+ if european_system:
+ @warning_ignore("integer_division")
+ return int(exponent / 3) / 2
+ @warning_ignore("integer_division")
+ return int(exponent / 3) - 1
+
+
+func _latinPrefix(european_system) -> String:
+ var ones := _latinPower(european_system) % 10
+ var tens := int(_latinPower(european_system) / floor(10)) % 10
+ @warning_ignore("integer_division")
+ var hundreds := int(_latinPower(european_system) / 100) % 10
+ @warning_ignore("integer_division")
+ var millias := int(_latinPower(european_system) / 1000) % 10
+
+ var prefix := ""
+ if _latinPower(european_system) < 10:
+ prefix = latin_special[ones] + options.reading_separator + latin_tens[tens] + options.reading_separator + latin_hundreds[hundreds]
+ else:
+ prefix = latin_hundreds[hundreds] + options.reading_separator + latin_ones[ones] + options.reading_separator + latin_tens[tens]
+
+ for _i in range(millias):
+ prefix = "millia" + options.reading_separator + prefix
+
+ return prefix.lstrip(options.reading_separator).rstrip(options.reading_separator)
+
+
+func _tillionOrIllion(european_system) -> String:
+ if exponent < 6:
+ return ""
+ var powerKilo := _latinPower(european_system) % 1000
+ if powerKilo < 5 and powerKilo > 0 and _latinPower(european_system) < 1000:
+ return ""
+ if (
+ powerKilo >= 7 and powerKilo <= 10
+ or int(powerKilo / floor(10)) % 10 == 1
+ ):
+ return "i"
+ return "ti"
+
+
+func _llionOrLliard(european_system) -> String:
+ if exponent < 6:
+ return ""
+ if int(exponent/floor(3)) % 2 == 1 and european_system:
+ return "lliard"
+ return "llion"
+
+
+func getLongName(european_system = false, prefix="") -> String:
+ if exponent < 6:
+ return ""
+ else:
+ return prefix + _latinPrefix(european_system) + options.reading_separator + _tillionOrIllion(european_system) + _llionOrLliard(european_system)
+
+
+## Converts the Big Number into a string (in American Long Name format)
+func toAmericanName(no_decimals_on_small_values = false) -> String:
+ return toLongName(no_decimals_on_small_values, false)
+
+
+## Converts the Big Number into a string (in European Long Name format)
+func toEuropeanName(no_decimals_on_small_values = false) -> String:
+ return toLongName(no_decimals_on_small_values, true)
+
+
+## Converts the Big Number into a string (in Latin Long Name format)
+func toLongName(no_decimals_on_small_values = false, european_system = false) -> String:
+ if exponent < 6:
+ if exponent > 2:
+ return toPrefix(no_decimals_on_small_values) + options.suffix_separator + options.thousand_name
+ else:
+ return toPrefix(no_decimals_on_small_values)
+
+ var suffix = _latinPrefix(european_system) + options.reading_separator + _tillionOrIllion(european_system) + _llionOrLliard(european_system)
+
+ return toPrefix(no_decimals_on_small_values) + options.suffix_separator + suffix
+
+
+## Converts the Big Number into a string (in Metric Symbols format)
+func toMetricSymbol(no_decimals_on_small_values = false) -> String:
+ @warning_ignore("integer_division")
+ var target := int(exponent / 3)
+
+ if not suffixes_metric_symbol.has(str(target)):
+ return toScientific()
+ else:
+ return toPrefix(no_decimals_on_small_values) + options.suffix_separator + suffixes_metric_symbol[str(target)]
+
+
+## Converts the Big Number into a string (in Metric Name format)
+func toMetricName(no_decimals_on_small_values = false) -> String:
+ @warning_ignore("integer_division")
+ var target := int(exponent / 3)
+
+ if not suffixes_metric_name.has(str(target)):
+ return toScientific()
+ else:
+ return toPrefix(no_decimals_on_small_values) + options.suffix_separator + suffixes_metric_name[str(target)]
+
+# HACK: This function is wasteful and requires remaking.
+# It adds new entries to the dictionary suffixes_aa instead of generating the suffixes
+# like the other functions
+## Converts the Big Number into a string (in AA format)
+## @deprecated
+func toAA(no_decimals_on_small_values = false, use_thousand_symbol = true, force_decimals=false) -> String:
+ @warning_ignore("integer_division")
+ var target := int(exponent / 3)
+ var aa_index := str(target)
+ var suffix := ""
+
+ if not suffixes_aa.has(aa_index):
+ var offset := target + 22
+ var base := alphabet_aa.size()
+ while offset > 0:
+ offset -= 1
+ var digit := offset % base
+ suffix = alphabet_aa[digit] + suffix
+ offset /= base
+ suffixes_aa[aa_index] = suffix
+ else:
+ suffix = suffixes_aa[aa_index]
+
+ if not use_thousand_symbol and target == 1:
+ suffix = ""
+
+ var prefix = toPrefix(no_decimals_on_small_values, use_thousand_symbol, force_decimals)
+
+ return prefix + options.suffix_separator + suffix