using System; namespace UVC.Extension { /// /// 숫자 관련 확장 메서드를 제공하는 클래스입니다. /// public static class NumberEx { /// /// 바이트 단위의 숫자를 사람이 읽기 쉬운 KB, MB, GB 등의 형태로 변환합니다. /// 1024.ToSizeSuffix() => 1KB /// https://stackoverflow.com/questions/14488796/does-net-provide-an-easy-way-convert-bytes-to-kb-mb-gb-etc /// /// 변환할 바이트 크기 /// 소수점 자릿수 (기본값: 1) /// 단위가 포함된 크기 문자열 (예: "1.5 KB") /// decimalPlaces가 0보다 작은 경우 발생 /// /// /// // 바이트 값을 크기 단위와 함께 표시 /// long fileSize = 1536; /// string readableSize = fileSize.ToSizeSuffix(); // "1.5 KB" 반환 /// /// // 소수점 2자리까지 표시 /// string preciseSize = fileSize.ToSizeSuffix(2); // "1.50 KB" 반환 /// /// // 더 큰 값 변환 /// long bigFileSize = 1073741824; // 1GB /// string bigSize = bigFileSize.ToSizeSuffix(); // "1.0 GB" 반환 /// /// public static string ToSizeSuffix(this long value, int decimalPlaces = 1) { if (decimalPlaces < 0) { throw new ArgumentOutOfRangeException("decimalPlaces"); } if (value < 0) { return "-" + ToSizeSuffix(-value, decimalPlaces); } if (value == 0) { return string.Format("{0:n" + decimalPlaces + "} bytes", 0); } // mag는 단위를 나타냄: 0=바이트, 1=KB, 2=MB 등 int mag = (int)Math.Log(value, 1024); // 1L << (mag * 10) == 2 ^ (10 * mag) // [즉, mag에 해당하는 단위의 바이트 수] decimal adjustedSize = (decimal)value / (1L << (mag * 10)); // 반올림했을 때 1000 이상이 되는 경우 단위를 한 단계 올림 if (Math.Round(adjustedSize, decimalPlaces) >= 1000) { mag += 1; adjustedSize /= 1024; } string[] SizeSuffixes = { "bytes", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB" }; return string.Format("{0:n" + decimalPlaces + "} {1}", adjustedSize, SizeSuffixes[mag]); } /// /// 숫자가 지정된 범위 내에 있는지 확인합니다. /// /// 비교 가능한 숫자 타입 /// 검사할 값 /// 최소값 (포함) /// 최대값 (포함) /// 값이 지정된 범위 내에 있으면 true, 그렇지 않으면 false /// /// /// int score = 85; /// bool isInRange = score.IsBetween(0, 100); // true 반환 /// /// float temperature = -5.5f; /// bool isValidTemp = temperature.IsBetween(-10f, 40f); // true 반환 /// /// public static bool IsBetween(this T value, T min, T max) where T : IComparable { return value.CompareTo(min) >= 0 && value.CompareTo(max) <= 0; } /// /// 값을 지정된 최소값과 최대값 사이로 제한합니다. /// /// 비교 가능한 숫자 타입 /// 제한할 값 /// 최소값 /// 최대값 /// 최소값과 최대값 사이로 제한된 값 /// /// /// int health = -10; /// int clampedHealth = health.Clamp(0, 100); // 0 반환 /// /// float speed = 120.5f; /// float clampedSpeed = speed.Clamp(0f, 100f); // 100f 반환 /// /// public static T Clamp(this T value, T min, T max) where T : IComparable { if (value.CompareTo(min) < 0) return min; if (value.CompareTo(max) > 0) return max; return value; } /// /// 숫자를 백분율로 변환합니다. /// /// 변환할 값 (0.0~1.0) /// 소수점 자릿수 /// 백분율 문자열 (예: "85%") /// /// /// float progress = 0.85f; /// string percent = progress.ToPercentString(); // "85.0%" 반환 /// /// double ratio = 0.7525; /// string precisePercent = ratio.ToPercentString(2); // "75.25%" 반환 /// /// public static string ToPercentString(this float value, int decimalPlaces = 1) { return string.Format("{0:n" + decimalPlaces + "}%", value * 100); } public static string ToPercentString(this double value, int decimalPlaces = 1) { return string.Format("{0:n" + decimalPlaces + "}%", value * 100); } /// /// 초 단위 시간을 시:분:초 형식의 문자열로 변환합니다. /// /// 초 단위 시간 /// 시:분:초 형식의 문자열 /// /// /// int gameTime = 3725; // 1시간 2분 5초 /// string formattedTime = gameTime.ToTimeString(); // "01:02:05" 반환 /// /// float recordTime = 135.5f; // 2분 15.5초 /// string shortTime = recordTime.ToTimeString(); // "00:02:16" 반환 (반올림됨) /// /// public static string ToTimeString(this int seconds) { TimeSpan time = TimeSpan.FromSeconds(seconds); return time.ToString(@"hh\:mm\:ss"); } public static string ToTimeString(this float seconds) { TimeSpan time = TimeSpan.FromSeconds((double)seconds); return time.ToString(@"hh\:mm\:ss"); } /// /// 숫자를 서수형 문자열로 변환합니다 (1st, 2nd, 3rd 등). /// /// 변환할 숫자 /// 서수형 문자열 /// /// /// int rank = 1; /// string rankString = rank.ToOrdinal(); // "1st" 반환 /// /// for (int i = 1; i <= 5; i++) /// { /// Console.WriteLine(i.ToOrdinal()); // "1st", "2nd", "3rd", "4th", "5th" 출력 /// } /// /// public static string ToOrdinal(this int number) { string suffix = "번째"; return number + suffix; } /// /// 숫자의 각 자리 합을 계산합니다. /// /// 계산할 숫자 /// 각 자리 숫자의 합 /// /// /// int number = 12345; /// int digitSum = number.SumOfDigits(); // 1+2+3+4+5 = 15 반환 /// /// public static int SumOfDigits(this int number) { int sum = 0; number = Math.Abs(number); while (number > 0) { sum += number % 10; number /= 10; } return sum; } /// /// 두 숫자 사이의 선형 보간된 값을 계산합니다. /// /// 시작값 /// 종료값 /// 보간 비율 (0.0 ~ 1.0) /// 보간된 값 /// /// /// float min = 0f; /// float max = 100f; /// float half = min.Lerp(max, 0.5f); // 50f 반환 /// /// // 부드러운 이동 애니메이션 예제 /// float startPosition = 0f; /// float endPosition = 10f; /// float t = 0.3f; // 30% 이동 /// float currentPosition = startPosition.Lerp(endPosition, t); // 3f 반환 /// /// public static float Lerp(this float start, float end, float t) { t = Math.Clamp(t, 0f, 1f); return start + (end - start) * t; } /// /// 숫자를 가장 가까운 배수로 반올림합니다. /// /// 반올림할 값 /// 배수 단위 /// 가장 가까운 배수로 반올림된 값 /// /// /// int price = 1242; /// int roundedPrice = price.RoundToNearest(100); // 1200 반환 /// /// float value = 3.7f; /// float rounded = value.RoundToNearest(0.5f); // 3.5f 반환 /// /// public static int RoundToNearest(this int value, int factor) { return (int)Math.Round((double)value / factor) * factor; } public static float RoundToNearest(this float value, float factor) { return (float)Math.Round(value / factor) * factor; } } }