
3D방치형 힐링 게임을 만들게 되면서 자동재화의 수치가 엄청나게 올라가면서 BigInteger의 중요성을 알게되어 이렇게 한번 정리를 해야겠다.
오늘 배운 것
오늘은 C#에서 큰 숫자를 다룰 때 BigInteger 타입을 사용하는 이유와 숫자를 사람이 읽기 쉬운 형식으로 포맷팅하는 방법에 대해 배웠습니다.
BigInteger는 매우 큰 숫자를 표현할 수 있는 임의 정밀도의 정수 타입입니다. int나 long 같은 기본 정수 타입은 고정된 크기를 가지며, 매우 큰 숫자를 처리할 수 없습니다. BigInteger는 이러한 한계를 극복하여 수십, 수백 자리의 숫자도 처리할 수 있습니다.
범위 제한:
int는 32비트 정수로 -2,147,483,648에서 2,147,483,647까지 표현할 수 있습니다.
long은 64비트 정수로 -9,223,372,036,854,775,808에서 9,223,372,036,854,775,807까지 표현할 수 있습니다.
하지만, BigInteger는 이보다 훨씬 큰 숫자를 처리할 수 있습니다.
오버플로우 방지:
int와 long은 범위를 초과하는 숫자를 처리하려 하면 오버플로우가 발생하여 잘못된 결과를 초래할 수 있습니다.
BigInteger는 임의 정밀도를 가지므로 오버플로우가 발생하지 않습니다.
큰 숫자를 사람이 읽기 쉬운 형식으로 포맷하기 위해 단위(K, M, B, T, P, Q 등)를 사용합니다. 아래는 BigInteger 값을 포맷하여 문자열로 변환하는 메서드입니다:
public static class BigIntegerUtils
{
public static string FormatBigInteger(BigInteger number)
{
if (number >= BigInteger.Pow(10, 60))
return ((double)number / (double)BigInteger.Pow(10, 60)).ToString("0.##") + "n";
if (number >= BigInteger.Pow(10, 57))
return ((double)number / (double)BigInteger.Pow(10, 57)).ToString("0.##") + "m";
if (number >= BigInteger.Pow(10, 54))
return ((double)number / (double)BigInteger.Pow(10, 54)).ToString("0.##") + "l";
if (number >= BigInteger.Pow(10, 51))
return ((double)number / (double)BigInteger.Pow(10, 51)).ToString("0.##") + "k";
if (number >= BigInteger.Pow(10, 48))
return ((double)number / (double)BigInteger.Pow(10, 48)).ToString("0.##") + "j";
if (number >= BigInteger.Pow(10, 45))
return ((double)number / (double)BigInteger.Pow(10, 45)).ToString("0.##") + "i";
if (number >= BigInteger.Pow(10, 42))
return ((double)number / (double)BigInteger.Pow(10, 42)).ToString("0.##") + "h";
if (number >= BigInteger.Pow(10, 39))
return ((double)number / (double)BigInteger.Pow(10, 39)).ToString("0.##") + "g";
if (number >= BigInteger.Pow(10, 36))
return ((double)number / (double)BigInteger.Pow(10, 36)).ToString("0.##") + "f";
if (number >= BigInteger.Pow(10, 33))
return ((double)number / (double)BigInteger.Pow(10, 33)).ToString("0.##") + "e";
if (number >= BigInteger.Pow(10, 30))
return ((double)number / (double)BigInteger.Pow(10, 30)).ToString("0.##") + "d";
if (number >= BigInteger.Pow(10, 27))
return ((double)number / (double)BigInteger.Pow(10, 27)).ToString("0.##") + "c";
if (number >= BigInteger.Pow(10, 24))
return ((double)number / (double)BigInteger.Pow(10, 24)).ToString("0.##") + "b";
if (number >= BigInteger.Pow(10, 21))
return ((double)number / (double)BigInteger.Pow(10, 21)).ToString("0.##") + "a";
if (number >= BigInteger.Pow(10, 18))
return ((double)number / (double)BigInteger.Pow(10, 18)).ToString("0.##") + "Q";
if (number >= BigInteger.Pow(10, 15))
return ((double)number / (double)BigInteger.Pow(10, 15)).ToString("0.##") + "P";
if (number >= BigInteger.Pow(10, 12))
return ((double)number / (double)BigInteger.Pow(10, 12)).ToString("0.##") + "T";
if (number >= BigInteger.Pow(10, 9))
return ((double)number / (double)BigInteger.Pow(10, 9)).ToString("0.##") + "B";
if (number >= BigInteger.Pow(10, 6))
return ((double)number / (double)BigInteger.Pow(10, 6)).ToString("0.##") + "M";
if (number >= BigInteger.Pow(10, 3))
return ((double)number / (double)BigInteger.Pow(10, 3)).ToString("0.##") + "K";
return number.ToString();
}
}
BigInteger.Parse("24726059949757700000000000000000000000000") 값은 10^40 이상의 숫자이므로, 이 값은 "24.73e"로 포맷됩니다.
BigInteger.Parse("33820000000") 값은 10^10에 해당하므로, "33.82B"로 포맷됩니다.
BigInteger 타입을 사용하면 매우 큰 숫자도 정확하게 다룰 수 있다는 것을 배웠습니다. 숫자를 사람이 읽기 쉽게 포맷하는 것도 중요하다는 것을 느꼈습니다. 앞으로도 큰 숫자를 다룰 때는 BigInteger를 적극 활용해야겠습니다.