Last active
April 27, 2021 11:09
-
-
Save dronir/8a32f25f5fb9d2799c80feb523fa0c07 to your computer and use it in GitHub Desktop.
Names of numbers in Finnish
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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