如何高效将int转换为指定小数位的decimal?现有实现效率偏低
Great question—your current string-based approach works, but the string manipulation and parsing add unnecessary memory overhead and slow down execution, especially if this function gets called frequently. Let's replace that with a pure numeric, zero-string-operation solution that's far more efficient.
The Optimal Solution: Use Decimal's Constructor Directly
The .NET decimal type has a constructor that lets you explicitly set the number of decimal places (scale) directly, without any division or string parsing. This is the fastest possible way to achieve your goal because it constructs the decimal value directly in memory:
decimal Int2Dec(int number, int precision) { // Validate input to avoid invalid scale values (decimal supports 0-28 decimal places) if (precision is < 0 or > 28) throw new ArgumentOutOfRangeException( nameof(precision), "Precision must be between 0 and 28 inclusive."); // The constructor parameters: // - lo: The low 32 bits of the decimal value (our int fits perfectly here) // - mid/hi: Middle and high 32 bits (0 for int values) // - isNegative: Whether the value is negative (derived from our int's sign) // - scale: Number of decimal places to apply return new decimal( lo: Math.Abs(number), mid: 0, hi: 0, isNegative: number < 0, scale: (byte)precision); }
How This Works
When you use this constructor, the integer number is treated as the unscaled value of the decimal. The scale parameter tells the decimal type to divide that unscaled value by 10^precision to get the final result:
- For
Int2Dec(2423, 2): Unscaled value is 2423, scale=2 →2423 / 10² = 24.23 - For
Int2Dec(2423, 3): Unscaled value is 2423, scale=3 →2423 / 10³ = 2.423
Why This Is Better Than Your Original Approach
- No string allocation: Your current method creates a string (e.g., "100" for precision=2) which adds garbage collection overhead.
- No parsing: Avoids converting strings to decimals, which is a relatively expensive operation.
- Direct memory construction: This is a low-level operation that skips all intermediate steps, making it orders of magnitude faster for repeated calls.
Alternative: Math-Based Division (If You Prefer Explicit Logic)
If you want a more readable approach without using the constructor's low-level parameters, you can compute the divisor as a decimal directly (still no strings involved):
decimal Int2Dec(int number, int precision) { if (precision is < 0 or > 28) throw new ArgumentOutOfRangeException(nameof(precision), "Precision must be 0-28."); decimal divisor = 1m; for (int i = 0; i < precision; i++) { divisor *= 10m; } return number / divisor; }
This is still way faster than your string method, though slightly less efficient than the constructor approach because of the loop. For small precision values (most common use cases), the performance difference is negligible.
内容的提问来源于stack exchange,提问作者Mike Jones

