철수는 매우 큰 수들의 곱을 구하고자 했으나, 오버플로우로 인하여 제대로된 값을 구하지 못했다. 철수를 위해 매우 큰 수들의 곱을 구해주는 프로그램을 만들어 주자.
조건) 1.입력값은 모두 1천만 이하의 자연수로 구성된다. 2.출력값의 형태는 다음을 따른다. 1,234,567,890 또는 1234567890 (부동 소수점 표현법은 불허한다.)
예시) 34566789 * 9989953^ 5 결과 : 3,439,349,130,987,378,995,741,000,108,452,472,269,377,477 (또는) 3439349130987378995741000108452472269377477
242896 * 2345987 * 3948562 * 2673851 * 2349863 * 2 * 9873645 * 5728364 결과: 1,599,200,004,322,211,514,880,952,175,873,148,802,507,070,720 (또는) 1599200004322211514880952175873148802507070720
//레벨 2 예상
9개의 풀이가 있습니다.
JAVA
자바로 작성하였으며, Map과 HashMap을 사용했습니다. 현재 있는 코드는 다른 기능도 포함하기에 쓸모없는 부분이 있을 수 있습니다.
package Testing;
import java.util.HashMap;
import java.util.Map;
public class InfiniteInt {
public static void main(String[] args){
Number num1 = new Number(242896);
int multi[] = {2345987,3948562,2673851,2349863,2,9873645,5728364};
for(int temp:multi){
num1.multiflyNumber(temp);
}
System.out.println(num1.getNumber(','));
System.out.println(num1.getNumber());
}
}
class Number{
//a map reference for store each digits value
private Map<Integer,Integer> num = new HashMap<Integer,Integer>();
//initializing
Number(int input){
int length = String.valueOf(input).length();
for(int i = 0; i < length ; i++){
num.put(i, input % 10);
input /= 10;
}
}
Number(){
num.put(0,0);
}
void setNumber(int input){//Be careful!, the old value will removed...
int length = String.valueOf(input).length();
num.clear();
for(int i = 0; i < length ; i++){
num.put(i, input % 10);
input /= 10;
}
}
void addNumber(int input){
Number numTemp = new Number(input);
addNumber(numTemp);
}
void addNumber(Number numTemp){
int i = 0;
while(numTemp.getDigit(i) != -1){
int temp = (num.containsKey(i)? num.get(i) : 0) + numTemp.getDigit(i);
num.put(i, temp);
i++;
}
refactNumber();
}
void multiflyNumber(int input){
int i = 0;
while(num.containsKey(i)){
num.put(i , num.get(i) * input);
i++;
}
refactNumber();
}
void refactNumber(){
int i = 0;
if(!num.containsKey(0)){
return;
}
while(num.containsKey(i + 1) || num.get(i) >= 10){//stop when key:i + 1 is doesn't exist and value of key 1 less than 10
if(num.get(i) < 10){
i++;
continue;
}
int temp = (num.get(i) / 10) + (num.containsKey(i + 1) ? num.get(i + 1) : 0);
num.put((i + 1), temp);
num.put(i, num.get(i) % 10);
i++;
}
}
String getNumber(){
String value = "";
for(int i = 0; i < num.size(); i++){
value = num.get(i) + value;
}
return value;
}
String getNumber(char form){//you can get numbers formatted
String value = "";
for(int i = 0; i < num.size(); i++){
if(i % 3 == 0 && i != 0){
value = "," + value;
}
value = num.get(i) + value;
}
return value;//if form == "," ex) 12,345,678;
}
void printNumberHashMap(){
System.out.println(num.values());
}
int getDigit(int index){
if(num.containsKey(index)){
return num.get(index);
}else{
return -1;
}
}
}
Python
문제에서 주어진 계산 예에 대해 파이썬에서는 overflow 없이 바로 계산이 가능하나, BigNum 클래스를 만들어 각 자리별로 곱셈을 계산하고 연산자 오버로딩하는 방식으로 접근해보았습니다.
import itertools
class BigNum:
"""자연수 연산 클래스"""
def __init__(self, num: str):
self.numstr: str = num
# 1의 자리부터의 계산을 위한 inversed string
self.numstr_desc: str = self.numstr[::-1]
def __mul__(self, other):
"""곱셈 연산자(*) 매직 메소드"""
# 자리별 숫자의 곱셈 매칭을 위해 "0"으로 채운 zip
desc_grp = list(itertools.zip_longest(
self.numstr_desc, other.numstr_desc, fillvalue="0"))
length = len(desc_grp)
# 인덱스0 = 1의 자리의 곱셉값 저장, ..., 인덱스n = n자리의 곱셉값 저장
rst = [0] * int(max(len(self.numstr), len(other.numstr)) * 2 + 1)
# 각 자리수별로 숫자를 곱하고 곱셈값의 10의 자리는 다음 인덱스에 더함
for idx1 in range(length):
for idx2 in range(length):
baseidx = idx1 + idx2
digit_multi = int(desc_grp[idx2][0]) * int(desc_grp[idx1][1])
for i, v in enumerate(d for d in str(digit_multi)[::-1]):
rst[baseidx + i] += int(v)
# 각 자리별로 곱해진 결과 리스트 정리
for idx in range(len(rst) - 1):
if rst[idx] >= 10:
rst[idx + 1] += (rst[idx] // 10)
rst[idx] = rst[idx] % 10
# 곱셈결과를 새로운 인스턴스로 반환
return BigNum("".join(map(str, rst[::-1])).lstrip("0"))
def __pow__(self, power, modulo=None):
"""거듭제곱 연산자(**) 매직 메소드"""
# 거듭제곱 수만큼 곱셈 메소드 호출
rst = self
for _ in range(power - 1):
rst = self.__mul__(rst)
return rst
def __str__(self):
return self.numstr
if __name__ == '__main__':
case1rst = BigNum("34566789") * BigNum("9989953") ** 5
print(case1rst)
# "3439349130987378995741000108452472269377477"
case2rst = BigNum("242896") * BigNum("2345987") * BigNum("3948562") \
* BigNum("2673851") * BigNum("2349863") * BigNum("2") \
* BigNum("9873645") * BigNum("5728364")
print(case2rst)
# "1599200004322211514880952175873148802507070720"
{-# LANGUAGE FlexibleInstances, FlexibleContexts, TypeSynonymInstances #-}
import Data.List
type BigInt = [Int]
radix = 10
showBigInt :: BigInt -> String
showBigInt = reverse . (>>= show)
carry :: [Int] -> BigInt
carry [] = []
carry [0] = []
carry [n] = carry [n, 0]
carry (n:m:rest) = r : carry (m+q : rest)
where (q, r) = quotRem n radix
instance Num BigInt where
fromInteger = carry . pure . fromInteger
a + b = carry $ fmap sum $ transpose [a,b]
a * b = sum $ do
(pos, digit) <- zip [0..] b
pure $ replicate pos 0 ++ fmap (*digit) a
abs = undefined
signum = undefined
negate = undefined
import itertools
class BigNum: """자연수 연산 클래스"""
def __init__(self, num: str):
self.numstr: str = num
# 1의 자리부터의 계산을 위한 inversed string
self.numstr_desc: str = self.numstr[::-1]
def __mul__(self, other):
"""곱셈 연산자(*) 매직 메소드"""
# 자리별 숫자의 곱셈 매칭을 위해 "0"으로 채운 zip
desc_grp = list(itertools.zip_longest(
self.numstr_desc, other.numstr_desc, fillvalue="0"))
length = len(desc_grp)
# 인덱스0 = 1의 자리의 곱셉값 저장, ..., 인덱스n = n자리의 곱셉값 저장
rst = [0] * int(max(len(self.numstr), len(other.numstr)) * 2 + 1)
# 각 자리수별로 숫자를 곱하고 곱셈값의 10의 자리는 다음 인덱스에 더함
for idx1 in range(length):
for idx2 in range(length):
baseidx = idx1 + idx2
digit_multi = int(desc_grp[idx2][0]) * int(desc_grp[idx1][1])
for i, v in enumerate(d for d in str(digit_multi)[::-1]):
rst[baseidx + i] += int(v)
# 각 자리별로 곱해진 결과 리스트 정리
for idx in range(len(rst) - 1):
if rst[idx] >= 10:
rst[idx + 1] += (rst[idx] // 10)
rst[idx] = rst[idx] % 10
# 곱셈결과를 새로운 인스턴스로 반환
return BigNum("".join(map(str, rst[::-1])).lstrip("0"))
def __pow__(self, power, modulo=None):
"""거듭제곱 연산자(**) 매직 메소드"""
# 거듭제곱 수만큼 곱셈 메소드 호출
rst = self
for _ in range(power - 1):
rst = self.__mul__(rst)
return rst
def __str__(self):
return self.numstr
if name == 'main': case1rst = BigNum("34566789") * BigNum("9989953") ** 5 print(case1rst) # "3439349130987378995741000108452472269377477"
case2rst = BigNum("242896") * BigNum("2345987") * BigNum("3948562") \
* BigNum("2673851") * BigNum("2349863") * BigNum("2") \
* BigNum("9873645") * BigNum("5728364")
print(case2rst)
# "1599200004322211514880952175873148802507070720"
자바 math 에서 제공하는 BigInteger가 있더라구요. 저희들이 모르는 숨겨진 api가 많은 것 같습니다.
import java.math.BigInteger;
public class BigNum {
public static void main(String[] args) {
int[] input = {4,45621,88897,1234567,9987};
String[] plate = new String[input.length];
for (int i = 0; i < plate.length; i++) {
plate[i] = ""+input[i];
}
BigInteger result = new BigInteger("1");//new BigInteger 선언시 숫자형태의 String 데이터를 메개변수를 선언해야한다.
for (int i = 0; i < plate.length; i++) {
result = result.multiply(new BigInteger(plate[i]));// BigInteger 클래스의 곱하기 매서드
}
System.out.println(result);
}
}
X와 Y를 곱할 때 십의 자릿수 이상 문자열을 각각 A, B라 하고 일의 자릿수 문자를 각각 a, b라 하면 X * Y = 100AB + 10(Ab+aB) + ab 라는 공식을 recursion 형식으로 호출했습니다.
def AddStr(str1, str2):
result = ""
carry = 0
islast = False
len1 = len(str1)
len2 = len(str2)
k1 = len1-1
k2 = len2-1
while (not islast):
if (k1>=0):
x = int(str1[k1])
k1 = k1-1
else:
x = 0
if (k2>=0):
y = int(str2[k2])
k2 = k2-1
else:
y = 0
if (k1<0 and k2<0):
islast = True
s = carry+x+y
if (s>9):
s = s%10
carry = 1
else:
carry = 0
result = str(s) + result
if (islast and carry==1):
result = "1"+result
return result
def MultStr(str1, str2):
len1 = len(str1)
len2 = len(str2)
if (len1==1 and len2==1):
return str(int(str1)*int(str2))
if (len1>1):
A = str1[:len1-1]
a = str1[len1-1]
else:
a = str1
if (len2>1):
B = str2[:len2-1]
b = str2[len2-1]
else:
b = str2
if (len1==1):
return AddStr(MultStr(a,B)+"0",MultStr(a,b))
if (len2==1):
return AddStr(MultStr(b,A)+"0",MultStr(a,b))
return AddStr(AddStr(MultStr(A,B)+"00",str(int(a)*int(b))), AddStr(MultStr(a,B),MultStr(A,b))+"0")
InputStr = input("숫자*숫자*숫자 .. 형태로 입력하시오(각 1천만 이하): ")
InputList = InputStr.split('*')
OutputStr = "1"
for numstr in InputList:
OutputStr = MultStr(OutputStr, numstr)
print("답= ", OutputStr)
import java.math.BigInteger;
import java.util.Scanner;
public class NumEx1 {
public static void main(String[] args) {
Scanner scan= new Scanner(System.in);
int j=0;
int num;
int k=0;//횟수
System.out.print("숫자를 누르세요(0을 계산이 종료됩니다):");
num=scan.nextInt();
//BigInteger i[] = new BigInteger[100];
BigInteger sum =new BigInteger("1");
while(num !=0 ) {
k=0;
BigInteger number = BigInteger.valueOf(num);
sum = sum.multiply(number);
System.out.print("다음 수를 누르세요:없으면 0을 누르세요:");
num=scan.nextInt();
k++;
}
System.out.println(" =====> "+sum);
}//main
}//class
using System;
using System.Collections.Generic;
namespace solution
{
class Program
{
static void Main(string[] args)
{
//string problem = "34566789 * 9989953^ 5";
string problem = "242896 * 2345987 * 3948562 * 2673851 * 2349863 * 2 * 9873645 * 5728364";
Console.WriteLine("\n {0} = {1}", problem, productOfVeryLargeNumbers(problem));
}
private static string productOfVeryLargeNumbers(string problem)
{
List<List<int>> numList = new List<List<int>>();
string Lsu = "";
string Rsu = "";
char op = ' ';
for (int i = 0; i < problem.Length; i++)
{
if (problem[i] == ' ')
{
continue;
}
else if (problem[i] == '*' || problem[i] == '^')
{
if (op == '*')
{
putNumList(Rsu, numList);
multipleBigNum(numList);
Lsu = Rsu;
}
else if (op == '^')
{
poweBigNum(int.Parse(Rsu), Lsu, numList);
}
else
{
putNumList(Rsu, numList);
Lsu = Rsu;
}
Rsu = "";
op = problem[i];
}
else
{
Rsu += problem[i];
}
}
if(op == '*')
{
putNumList(Rsu, numList);
multipleBigNum(numList);
}
else if(op == '^')
poweBigNum(int.Parse(Rsu), Lsu, numList);
int N = numList[0].Count;
Lsu = "";
for (int i = 0; i < N; i++)
{
Lsu = numList[0][i] + Lsu;
if (i != N - 1 && i % 3 == 2)
Lsu = "," + Lsu;
}
return Lsu;
}
private static void poweBigNum(int v, string Lsu, List<List<int>> numList)
{
for (int i = 1; i < v; i++)
{
putNumList(Lsu, numList);
multipleBigNum(numList);
}
}
private static void putNumList(string su, List<List<int>> numList)
{
int N = su.Length - 1;
List<int> list = new List<int>();
for (int i = N; i >= 0; i--)
list.Add(int.Parse(su[i].ToString()));
numList.Add(new List<int>(list));
}
private static void multipleBigNum(List<List<int>> numList)
{
List<int> list = new List<int>();
int N = numList.Count - 1;
int gop = 0;
int up = 0;
for (int i = 0; i < numList[N].Count; i++)
{
gop = numList[N][i];
for (int j = 0; j < numList[N-1].Count; j++)
{
list.Add(0);
up = numList[N - 1][j] * gop + up + list[i + j];
list[i + j] = up % 10;
up = up / 10;
}
int cnt = i + numList[N - 1].Count;
while (up > 0)
{
list.Add(0);
list[cnt] += up;
up = list[cnt] / 10;
list[cnt++] %= 10;
}
}
N = list.Count - 1;
while(N >= 0 && list[N] == 0)
{
list.RemoveAt(N);
N--;
}
numList.Clear();
numList.Add(new List<int>(list));
}
}
}