Skip to content

Instantly share code, notes, and snippets.

@aaronfranke
Last active August 6, 2023 08:11
Show Gist options
  • Save aaronfranke/8b2c39bfbe48068c574e4daf2710c875 to your computer and use it in GitHub Desktop.
Save aaronfranke/8b2c39bfbe48068c574e4daf2710c875 to your computer and use it in GitHub Desktop.
IEEE-style floating-point format table generator (GDScript)
# IEEE-style floating-point format table generator (GDScript)
# Python version: https://gist.github.com/aaronfranke/0d1217e521c4ec784d39e92b5f039115
# GDScript version: https://gist.github.com/aaronfranke/8b2c39bfbe48068c574e4daf2710c875
extends Node
# SEMB values can describe any IEEE-like binary floating-point format.
var sign_bit: bool = true
var exponent_bits: int = 2
var mantissa_bits: int = 1
## Can be set to an integer. If null, the bias will be automatically determined
## to match IEEE formats, symmetric around 1. Specialized use cases may benefit
## from overriding this, but this should usually be kept as automatic.
var bias = null
func _ready() -> void:
assert(exponent_bits > 0, "Exponent bit amount cannot be zero or negative. A float must have at least 1 exponent bit, or else it's just an integer, loses Inf/NaN, etc.")
assert(mantissa_bits >= 0, "Mantissa bit amount cannot be negative. However, mantissa is allowed to have zero bits.")
if not bias is int:
bias = int(pow(2, exponent_bits - 1)) - 1
# Generate the mantissa row without an exponent bias.
var mantissa_base = _generate_mantissa_base(mantissa_bits)
# Generate the cells of the table.
var table_cell_rows: Array[Array] = _generate_table_data_cells(mantissa_base)
# Format the cells as a WikiText table.
var wikitext: String = _format_pretty_table_wikitext(table_cell_rows)
print(wikitext)
func _format_pretty_table_wikitext(table_cell_rows: Array[Array]) -> String:
var output_text: String = '{| class="wikitable" style="text-align:right; font-size:small"\n!\n! '
# Generate the header row.
var first_row: Array = table_cell_rows[0]
for i in range(first_row.size()):
var column_width = String(first_row[i]).length()
if i != 0:
output_text += " || "
output_text += ("… " + _int_to_bits(i, mantissa_bits)).lpad(column_width, " ")
# Generate the main rows.
var table_row_count: int = table_cell_rows.size()
for i in range(table_row_count):
output_text += "\n|-\n! "
if sign_bit:
@warning_ignore("integer_division")
output_text += "0 " if i < table_row_count / 2 else "1 "
output_text += _int_to_bits(i, exponent_bits) + " …\n"
var row: Array = table_cell_rows[i]
for j in range(row.size()):
if j == 0:
output_text += "| "
else:
output_text += " || "
output_text += row[j]
output_text += "\n|}"
return output_text
func _generate_table_data_cells(mantissa_base: Array[float]) -> Array[Array]:
var rows: Array[Array] = []
var column_widths: Array[int] = []
var exponent_range: int = int(pow(2, exponent_bits)) - 1
# Generate the main rows.
for i in range(exponent_range):
var row: Array = []
rows.append(row)
var exponent: int = i - bias
if i == 0:
exponent += 1
var multiplier = pow(2, exponent)
for j in range(mantissa_base.size()):
var mantissa_number: float = mantissa_base[j]
if i == 0:
column_widths.append(_starting_column_width())
mantissa_number -= 1.0
var stringified_number = str(mantissa_number * multiplier)
if stringified_number.length() > column_widths[j]:
column_widths[j] = stringified_number.length()
if sign_bit:
column_widths[j] += 1
row.append(stringified_number)
# Add the infinity/NaN row.
var inf_nan_row: Array = ["Inf"]
for i in range(mantissa_base.size() - 1):
inf_nan_row.append("NaN")
rows.append(inf_nan_row)
# If there is a sign bit, append a duplicate of every row, with a minus sign.
if sign_bit:
for row in rows.duplicate(true):
for cell_index in range(row.size()):
row[cell_index] = "−" + row[cell_index]
rows.append(row)
# Pad each column's entries to be the same length.
for i in range(rows.size()):
var row = rows[i]
for j in range(row.size()):
var column_width: int = column_widths[j]
row[j] = String(row[j]).lpad(column_width, " ")
return rows
func _starting_column_width() -> int:
var ret: int = 2 + mantissa_bits
if sign_bit:
if ret < 4:
return 4
else:
if ret < 3:
return 3
return ret
func _generate_mantissa_base(bits_amount: int) -> Array[float]:
var mantissa_base: Array[float] = []
var mantissa_step: float = pow(2, -bits_amount)
var mantissa_value: float = 1.0
while true:
mantissa_base.append(mantissa_value)
mantissa_value += mantissa_step
if mantissa_value >= 2.0:
break
return mantissa_base
func _int_to_bits(number: int, bits_amount: int) -> String:
var ret: String = ""
var digit_value: int = 1
for i in range(bits_amount):
if number & digit_value == 0:
ret = "0" + ret
else:
ret = "1" + ret
digit_value *= 2
return ret
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment