Compare commits

...

2 Commits

Author SHA1 Message Date
Bama Charan Chhandogi
062957ef27
Octal to Binary Convert (#8949)
* Octal to Binary Convert

* [pre-commit.ci] auto fixes from pre-commit.com hooks

for more information, see https://pre-commit.ci

* mention return type

* code scratch

* [pre-commit.ci] auto fixes from pre-commit.com hooks

for more information, see https://pre-commit.ci

* mentioned return type

* remove comment

* added documention and some test cases

* [pre-commit.ci] auto fixes from pre-commit.com hooks

for more information, see https://pre-commit.ci

* add another test case

* fixes documention

* [pre-commit.ci] auto fixes from pre-commit.com hooks

for more information, see https://pre-commit.ci

* Documention and test cases added

* [pre-commit.ci] auto fixes from pre-commit.com hooks

for more information, see https://pre-commit.ci

* documention problem solved

* [pre-commit.ci] auto fixes from pre-commit.com hooks

for more information, see https://pre-commit.ci

* error in exit 1

* [pre-commit.ci] auto fixes from pre-commit.com hooks

for more information, see https://pre-commit.ci

* Apply suggestions from code review

---------

Co-authored-by: BamaCharanChhandogi <b.c.chhandogi@gmailcom>
Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
Co-authored-by: Tianyi Zheng <tianyizheng02@gmail.com>
2023-08-20 05:40:23 -07:00
Tianyi Zheng
5ecb6baef8
Move and reimplement convert_number_to_words.py (#8998)
* Move and reimplement convert_number_to_words.py

- Move convert_number_to_words.py from web_programming/ to conversions/
- Reimplement the algorithm from scratch because the logic was very
  opaque and too heavily nested
- Add support for the Western numbering system (both short and long)
  because the original implementation only supported the Indian
  numbering system
- Add extensive doctests and error handling

* updating DIRECTORY.md

---------

Co-authored-by: github-actions <${GITHUB_ACTOR}@users.noreply.github.com>
2023-08-20 08:36:00 -04:00
4 changed files with 260 additions and 110 deletions

View File

@ -143,6 +143,7 @@
* [Binary To Decimal](conversions/binary_to_decimal.py) * [Binary To Decimal](conversions/binary_to_decimal.py)
* [Binary To Hexadecimal](conversions/binary_to_hexadecimal.py) * [Binary To Hexadecimal](conversions/binary_to_hexadecimal.py)
* [Binary To Octal](conversions/binary_to_octal.py) * [Binary To Octal](conversions/binary_to_octal.py)
* [Convert Number To Words](conversions/convert_number_to_words.py)
* [Decimal To Any](conversions/decimal_to_any.py) * [Decimal To Any](conversions/decimal_to_any.py)
* [Decimal To Binary](conversions/decimal_to_binary.py) * [Decimal To Binary](conversions/decimal_to_binary.py)
* [Decimal To Binary Recursion](conversions/decimal_to_binary_recursion.py) * [Decimal To Binary Recursion](conversions/decimal_to_binary_recursion.py)
@ -1203,7 +1204,6 @@
## Web Programming ## Web Programming
* [Co2 Emission](web_programming/co2_emission.py) * [Co2 Emission](web_programming/co2_emission.py)
* [Convert Number To Words](web_programming/convert_number_to_words.py)
* [Covid Stats Via Xpath](web_programming/covid_stats_via_xpath.py) * [Covid Stats Via Xpath](web_programming/covid_stats_via_xpath.py)
* [Crawl Google Results](web_programming/crawl_google_results.py) * [Crawl Google Results](web_programming/crawl_google_results.py)
* [Crawl Google Scholar Citation](web_programming/crawl_google_scholar_citation.py) * [Crawl Google Scholar Citation](web_programming/crawl_google_scholar_citation.py)

View File

@ -0,0 +1,205 @@
from enum import Enum
from typing import ClassVar, Literal
class NumberingSystem(Enum):
SHORT = (
(15, "quadrillion"),
(12, "trillion"),
(9, "billion"),
(6, "million"),
(3, "thousand"),
(2, "hundred"),
)
LONG = (
(15, "billiard"),
(9, "milliard"),
(6, "million"),
(3, "thousand"),
(2, "hundred"),
)
INDIAN = (
(14, "crore crore"),
(12, "lakh crore"),
(7, "crore"),
(5, "lakh"),
(3, "thousand"),
(2, "hundred"),
)
@classmethod
def max_value(cls, system: str) -> int:
"""
Gets the max value supported by the given number system.
>>> NumberingSystem.max_value("short") == 10**18 - 1
True
>>> NumberingSystem.max_value("long") == 10**21 - 1
True
>>> NumberingSystem.max_value("indian") == 10**19 - 1
True
"""
match (system_enum := cls[system.upper()]):
case cls.SHORT:
max_exp = system_enum.value[0][0] + 3
case cls.LONG:
max_exp = system_enum.value[0][0] + 6
case cls.INDIAN:
max_exp = 19
case _:
raise ValueError("Invalid numbering system")
return 10**max_exp - 1
class NumberWords(Enum):
ONES: ClassVar = {
0: "",
1: "one",
2: "two",
3: "three",
4: "four",
5: "five",
6: "six",
7: "seven",
8: "eight",
9: "nine",
}
TEENS: ClassVar = {
0: "ten",
1: "eleven",
2: "twelve",
3: "thirteen",
4: "fourteen",
5: "fifteen",
6: "sixteen",
7: "seventeen",
8: "eighteen",
9: "nineteen",
}
TENS: ClassVar = {
2: "twenty",
3: "thirty",
4: "forty",
5: "fifty",
6: "sixty",
7: "seventy",
8: "eighty",
9: "ninety",
}
def convert_small_number(num: int) -> str:
"""
Converts small, non-negative integers with irregular constructions in English (i.e.,
numbers under 100) into words.
>>> convert_small_number(0)
'zero'
>>> convert_small_number(5)
'five'
>>> convert_small_number(10)
'ten'
>>> convert_small_number(15)
'fifteen'
>>> convert_small_number(20)
'twenty'
>>> convert_small_number(25)
'twenty-five'
>>> convert_small_number(-1)
Traceback (most recent call last):
...
ValueError: This function only accepts non-negative integers
>>> convert_small_number(123)
Traceback (most recent call last):
...
ValueError: This function only converts numbers less than 100
"""
if num < 0:
raise ValueError("This function only accepts non-negative integers")
if num >= 100:
raise ValueError("This function only converts numbers less than 100")
tens, ones = divmod(num, 10)
if tens == 0:
return NumberWords.ONES.value[ones] or "zero"
if tens == 1:
return NumberWords.TEENS.value[ones]
return (
NumberWords.TENS.value[tens]
+ ("-" if NumberWords.ONES.value[ones] else "")
+ NumberWords.ONES.value[ones]
)
def convert_number(
num: int, system: Literal["short", "long", "indian"] = "short"
) -> str:
"""
Converts an integer to English words.
:param num: The integer to be converted
:param system: The numbering system (short, long, or Indian)
>>> convert_number(0)
'zero'
>>> convert_number(1)
'one'
>>> convert_number(100)
'one hundred'
>>> convert_number(-100)
'negative one hundred'
>>> convert_number(123_456_789_012_345) # doctest: +NORMALIZE_WHITESPACE
'one hundred twenty-three trillion four hundred fifty-six billion
seven hundred eighty-nine million twelve thousand three hundred forty-five'
>>> convert_number(123_456_789_012_345, "long") # doctest: +NORMALIZE_WHITESPACE
'one hundred twenty-three thousand four hundred fifty-six milliard
seven hundred eighty-nine million twelve thousand three hundred forty-five'
>>> convert_number(12_34_56_78_90_12_345, "indian") # doctest: +NORMALIZE_WHITESPACE
'one crore crore twenty-three lakh crore
forty-five thousand six hundred seventy-eight crore
ninety lakh twelve thousand three hundred forty-five'
>>> convert_number(10**18)
Traceback (most recent call last):
...
ValueError: Input number is too large
>>> convert_number(10**21, "long")
Traceback (most recent call last):
...
ValueError: Input number is too large
>>> convert_number(10**19, "indian")
Traceback (most recent call last):
...
ValueError: Input number is too large
"""
word_groups = []
if num < 0:
word_groups.append("negative")
num *= -1
if num > NumberingSystem.max_value(system):
raise ValueError("Input number is too large")
for power, unit in NumberingSystem[system.upper()].value:
digit_group, num = divmod(num, 10**power)
if digit_group > 0:
word_group = (
convert_number(digit_group, system)
if digit_group >= 100
else convert_small_number(digit_group)
)
word_groups.append(f"{word_group} {unit}")
if num > 0 or not word_groups: # word_groups is only empty if input num was 0
word_groups.append(convert_small_number(num))
return " ".join(word_groups)
if __name__ == "__main__":
import doctest
doctest.testmod()
print(f"{convert_number(123456789) = }")

View File

@ -0,0 +1,54 @@
"""
* Author: Bama Charan Chhandogi (https://github.com/BamaCharanChhandogi)
* Description: Convert a Octal number to Binary.
References for better understanding:
https://en.wikipedia.org/wiki/Binary_number
https://en.wikipedia.org/wiki/Octal
"""
def octal_to_binary(octal_number: str) -> str:
"""
Convert an Octal number to Binary.
>>> octal_to_binary("17")
'001111'
>>> octal_to_binary("7")
'111'
>>> octal_to_binary("Av")
Traceback (most recent call last):
...
ValueError: Non-octal value was passed to the function
>>> octal_to_binary("@#")
Traceback (most recent call last):
...
ValueError: Non-octal value was passed to the function
>>> octal_to_binary("")
Traceback (most recent call last):
...
ValueError: Empty string was passed to the function
"""
if not octal_number:
raise ValueError("Empty string was passed to the function")
binary_number = ""
octal_digits = "01234567"
for digit in octal_number:
if digit not in octal_digits:
raise ValueError("Non-octal value was passed to the function")
binary_digit = ""
value = int(digit)
for _ in range(3):
binary_digit = str(value % 2) + binary_digit
value //= 2
binary_number += binary_digit
return binary_number
if __name__ == "__main__":
import doctest
doctest.testmod()

View File

@ -1,109 +0,0 @@
import math
def convert(number: int) -> str:
"""
Given a number return the number in words.
>>> convert(123)
'OneHundred,TwentyThree'
"""
if number == 0:
words = "Zero"
return words
else:
digits = math.log10(number)
digits = digits + 1
singles = {}
singles[0] = ""
singles[1] = "One"
singles[2] = "Two"
singles[3] = "Three"
singles[4] = "Four"
singles[5] = "Five"
singles[6] = "Six"
singles[7] = "Seven"
singles[8] = "Eight"
singles[9] = "Nine"
doubles = {}
doubles[0] = ""
doubles[2] = "Twenty"
doubles[3] = "Thirty"
doubles[4] = "Forty"
doubles[5] = "Fifty"
doubles[6] = "Sixty"
doubles[7] = "Seventy"
doubles[8] = "Eighty"
doubles[9] = "Ninety"
teens = {}
teens[0] = "Ten"
teens[1] = "Eleven"
teens[2] = "Twelve"
teens[3] = "Thirteen"
teens[4] = "Fourteen"
teens[5] = "Fifteen"
teens[6] = "Sixteen"
teens[7] = "Seventeen"
teens[8] = "Eighteen"
teens[9] = "Nineteen"
placevalue = {}
placevalue[2] = "Hundred,"
placevalue[3] = "Thousand,"
placevalue[5] = "Lakh,"
placevalue[7] = "Crore,"
temp_num = number
words = ""
counter = 0
digits = int(digits)
while counter < digits:
current = temp_num % 10
if counter % 2 == 0:
addition = ""
if counter in placevalue and current != 0:
addition = placevalue[counter]
if counter == 2:
words = singles[current] + addition + words
elif counter == 0:
if ((temp_num % 100) // 10) == 1:
words = teens[current] + addition + words
temp_num = temp_num // 10
counter += 1
else:
words = singles[current] + addition + words
else:
words = doubles[current] + addition + words
else:
if counter == 1:
if current == 1:
words = teens[number % 10] + words
else:
addition = ""
if counter in placevalue:
addition = placevalue[counter]
words = doubles[current] + addition + words
else:
addition = ""
if counter in placevalue:
if current != 0 and ((temp_num % 100) // 10) != 0:
addition = placevalue[counter]
if ((temp_num % 100) // 10) == 1:
words = teens[current] + addition + words
temp_num = temp_num // 10
counter += 1
else:
words = singles[current] + addition + words
counter += 1
temp_num = temp_num // 10
return words
if __name__ == "__main__":
import doctest
doctest.testmod()