diff --git a/app/Utils/BcMath.php b/app/Utils/BcMath.php new file mode 100644 index 0000000000..2b68052c5c --- /dev/null +++ b/app/Utils/BcMath.php @@ -0,0 +1,375 @@ += 0; + } + + /** + * Check if left number is less than right number using bcmath + * + * @param string|float|int $left + * @param string|float|int $right + * @param int|null $scale + * @return bool + */ + public static function lessThan($left, $right, ?int $scale = null): bool + { + return self::comp($left, $right, $scale) === -1; + } + + /** + * Check if left number is less than or equal to right number using bcmath + * + * @param string|float|int $left + * @param string|float|int $right + * @param int|null $scale + * @return bool + */ + public static function lessThanOrEqual($left, $right, ?int $scale = null): bool + { + return self::comp($left, $right, $scale) <= 0; + } + + /** + * Check if a number is zero using bcmath + * + * @param string|float|int $number + * @param int|null $scale + * @return bool + */ + public static function isZero($number, ?int $scale = null): bool + { + return self::equal($number, '0', $scale); + } + + /** + * Check if a number is positive using bcmath + * + * @param string|float|int $number + * @param int|null $scale + * @return bool + */ + public static function isPositive($number, ?int $scale = null): bool + { + return self::greaterThan($number, '0', $scale); + } + + /** + * Check if a number is negative using bcmath + * + * @param string|float|int $number + * @param int|null $scale + * @return bool + */ + public static function isNegative($number, ?int $scale = null): bool + { + return self::lessThan($number, '0', $scale); + } + + /** + * Get the absolute value using bcmath + * + * @param string|float|int $number + * @param int|null $scale + * @return string + */ + public static function abs($number, ?int $scale = null): string + { + $scale = $scale ?? self::DEFAULT_SCALE; + $number = (string)$number; + + if (self::isNegative($number, $scale)) { + return self::mul($number, '-1', $scale); + } + + return $number; + } + + /** + * Calculate percentage using bcmath + * + * @param string|float|int $part + * @param string|float|int $total + * @param int|null $scale + * @return string + */ + public static function percentage($part, $total, ?int $scale = null): string + { + $scale = $scale ?? self::DEFAULT_SCALE; + + if (self::isZero($total, $scale)) { + return '0'; + } + + return self::mul(self::div($part, $total, $scale + 2), '100', $scale); + } + + /** + * Calculate sum of an array of numbers using bcmath + * + * @param array $numbers + * @param int|null $scale + * @return string + */ + public static function sum(array $numbers, ?int $scale = null): string + { + $scale = $scale ?? self::DEFAULT_SCALE; + $result = '0'; + + foreach ($numbers as $number) { + $result = self::add($result, $number, $scale); + } + + return $result; + } + + /** + * Calculate average of an array of numbers using bcmath + * + * @param array $numbers + * @param int|null $scale + * @return string + */ + public static function avg(array $numbers, ?int $scale = null): string + { + $scale = $scale ?? self::DEFAULT_SCALE; + $count = count($numbers); + + if ($count === 0) { + return '0'; + } + + $sum = self::sum($numbers, $scale); + return self::div($sum, (string)$count, $scale); + } + + /** + * Format a number as currency string with proper precision + * + * @param string|float|int $number + * @param int $precision + * @return string + */ + public static function formatCurrency($number, int $precision = self::DEFAULT_SCALE): string + { + $rounded = self::round($number, $precision); + return number_format((float)$rounded, $precision, '.', ''); + } + + /** + * Convert a number to float for compatibility with existing code + * Use this sparingly and only when you need to pass values to functions that expect floats + * + * @param string|float|int $number + * @return float + */ + public static function toFloat($number): float + { + return (float)$number; + } + + /** + * Convert a number to string for consistent handling + * + * @param string|float|int $number + * @return string + */ + public static function toString($number): string + { + return (string)$number; + } +}