Skip to content

Instantly share code, notes, and snippets.

@dronir
Last active April 27, 2021 11:09
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save dronir/8a32f25f5fb9d2799c80feb523fa0c07 to your computer and use it in GitHub Desktop.
Save dronir/8a32f25f5fb9d2799c80feb523fa0c07 to your computer and use it in GitHub Desktop.
Names of numbers in Finnish
from sys import argv
# Function to produce verbal names of Finnish numbers up to 10^12 - 1.
# If run on the command line, takes an integer parameter and prints the
# name of that number.
# Requires Python 3 (you should not be running Python 2.x in the year 2020 anyway).
INDIVIDUALS = {
0 : "", # zero is set to empty string here for convenience below
1 : "yksi",
2 : "kaksi",
3 : "kolme",
4 : "neljä",
5 : "viisi",
6 : "kuusi",
7 : "seitsemän",
8 : "kahdeksan",
9 : "yhdeksän",
10 : "kymmenen",
100 : "sata",
1000 : "tuhat",
1000000 : "miljoona",
1000000000 : "miljardi"
}
SUFFIXES = ["", "tuhatta", "miljoonaa", "miljardia"]
def numbername(n):
"""Return the Finnish name of the number n, up to absolute value 10**12 - 1.
The negative of a number returns "miinus N" for completeness' sake.
"""
if abs(n) > 999999999999:
raise ValueError("Cannot compute for abs(n) greater than 10^12 - 1.")
elif n < 0:
# Negative numbers are "miinus" and whatever the absolute value is.
return f"miinus {numbername(-n)}"
elif n == 0:
# Zero is handled here separately because it's convenient later to have
# the empty string for zero in the individuals table.
return "nolla"
elif n in INDIVIDUALS.keys():
# Numbers with unique names, given in the individuals table.
return INDIVIDUALS[n]
elif n < 20:
# Numbers between 11...19, inclusive
# e.g. 13 == "kolmetoista"
second_digit = int(str(n)[1])
X = INDIVIDUALS[second_digit]
return f"{X}toista"
elif n < 100:
# Numbers between 20...99, inclusive
# e.g. 43 == "neljäkymmentäkolme"
s = str(n)
first_digit = int(s[0])
second_digit = int(s[1])
X = INDIVIDUALS[first_digit]
Y = INDIVIDUALS[second_digit]
return f"{X}kymmentä{Y}"
elif n < 200:
# Numbers between 100...199, inclusive
# e.g. 143 == "sataneljäkymmentäkolme"
X = numbername(n-100)
return f"sata{X}"
elif n < 1000:
# Numbers between 200...999, inclusive
# e.g. 343 == "kolmesataaneljäkymmentäkolme"
first_digit = int(str(n)[0])
X = numbername(first_digit)
Y = numbername(n-100*first_digit) if n%100 != 0 else ""
return f"{X}sataa{Y}"
else:
# Turn the number into four parts of three digits, padding with zeroes.
# These parts are the billions, millions, thousands and sub-thousand digits.
s = f"{n:012d}"
parts = [int(s[3*k : 3*(k+1)]) for k in range(4)]
result = []
# Work through the parts in reverse order (start with sub-thousand).
for k, part in enumerate(reversed(parts)):
if part == 0:
# If a part is zero, it doesn't contribute to the name.
result.append("")
elif part == 1:
# If a part is exactly 1, its name is the singular word,
# which are found in the individuals table.
value = part * 10**(3*k)
result.append(INDIVIDUALS[value])
else:
# If a part is not 1, it has the name of the three-digit part itself,
# and a plural suffix for thousands/millions/billions.
X = numbername(part)
suffix = SUFFIXES[k]
result.append(f"{X}{suffix}")
# Join the part names back together, reversing again
return "".join(reversed(result))
if __name__=="__main__":
N = int(argv[1])
print(f"{N} is '{numbername(N)}'")
def test_numbers():
assert numbername(0) == "nolla"
assert numbername(101) == "satayksi"
assert numbername(10020) == "kymmenentuhattakaksikymmentä"
assert numbername(20010020) == "kaksikymmentämiljoonaakymmenentuhattakaksikymmentä"
assert numbername(5020010020) == "viisimiljardiakaksikymmentämiljoonaakymmenentuhattakaksikymmentä"
assert numbername(-53) == "miinus viisikymmentäkolme"
from finnishnumbers import numbername
from sys import argv
# Print Finnish number name lengths for the OEIS, sequence A001050.
# Outputs in b-file format, up to an integer given on the command line.
if __name__=="__main__":
N = int(argv[1])
for i in range(N+1):
print(f"{i} {len(numbername(i))}")
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment