我想用一个增加小数的最小小数部分,例如
decimal d = 0.01
d++
d == 0.02
或
decimal d = 0.000012349
d++
d == 0.000012350
我该怎么做?
答案 0 :(得分:12)
十进制类型(.NET 2.0及更高版本)保留重要的尾随零,这是计算结果或解析字符串的结果。例如。 1.2 * 0.5 = 0.60(精确到两个小数位的两个数相乘,得到的结果精确到2位小数,即使第二个小数位为零):
decimal result = 1.2M * 0.5M;
Console.WriteLine(result.ToString()); // outputs 0.60
以下假设您要考虑十进制值中的所有有效数字,即
decimal d = 1.2349M; // original 1.2349;
d = IncrementLastDigit(d); // result is 1.2350;
d = IncrementLastDigit(d); // result is 1.2351; (not 1.2360).
但是,如果你想首先删除尾随零,你可以这样做,例如使用in this answer技术。
没有任何内置功能可以做到这一点。你必须自己做(a)确定小数后有多少位数,然后(b)加上适当的数量。
要确定小数点后有多少位数,您可以将其格式化为字符串,然后对它们进行计数,或者更有效地调用decimal.GetBits(),其结果是包含四个整数的四个整数数组缩放因子在第四个整数的第16-23位。
完成后,您可以轻松计算要添加到小数值的所需值。
这是一个使用GetBits的实现,对于负数,它从零开始“递增”IncrementLastDigit(-1.234M)=> -1.235M。
static decimal IncrementLastDigit(decimal value)
{
int[] bits1 = decimal.GetBits(value);
int saved = bits1[3];
bits1[3] = 0; // Set scaling to 0, remove sign
int[] bits2 = decimal.GetBits(new decimal(bits1) + 1);
bits2[3] = saved; // Restore original scaling and sign
return new decimal(bits2);
}
或者这是另一种选择(可能稍微优雅一点):
static decimal GetScaledOne(decimal value)
{
int[] bits = decimal.GetBits(value);
// Generate a value +1, scaled using the same scaling factor as the input value
bits[0] = 1;
bits[1] = 0;
bits[2] = 0;
bits[3] = bits[3] & 0x00FF0000;
return new decimal(bits);
}
static decimal IncrementLastDigit(decimal value)
{
return value < 0 ? value - GetScaledOne(value) : value + GetScaledOne(value);
}
答案 1 :(得分:1)
我想出了一个与Joe不同的新解决方案,它应该会导致性能的微小提升。
public static decimal IncrementLowestDigit(this decimal value, int amount)
{
int[] bits = decimal.GetBits(value);
if (bits[0] < 0 && amount + bits[0] >= 0)
{
bits[1]++;
if (bits[1] == 0)
{
bits[2]++;
}
}
bits[0] += amount;
return new decimal(bits);
}
<强>测试强>
我用Joe的方法测试了我的结果。
private static void Test(int l, int m, int h, int e, int times)
{
decimal a = new decimal(new[] { l, m, h, e });
decimal b = a.IncrementLowestDigit(times);
decimal c = IncrementLastDigit(a, times);
Console.WriteLine(a);
Console.WriteLine(b);
Console.WriteLine(c);
Console.WriteLine();
}
Test(0, 0, 0, 0x00000000, 1);
Test(0, 0, 0, 0x00000000, 2);
Test(0, 0, 0, 0x00010000, 1);
Test(0, 0, 0, 0x00010000, 2);
Test(0, 0, 0, 0x00020000, 1);
Test(0, 0, 0, 0x00020000, 2);
Test(-1, 0, 0, 0x00000000, 1);
Test(-1, 0, 0, 0x00000000, 2);
Test(-1, 0, 0, 0x00010000, 1);
Test(-1, 0, 0, 0x00010000, 2);
Test(-1, 0, 0, 0x00020000, 1);
Test(-1, 0, 0, 0x00020000, 2);
Test(-2, 0, 0, 0x00000000, 1);
Test(-2, 0, 0, 0x00000000, 2);
Test(-2, 0, 0, 0x00010000, 1);
Test(-2, 0, 0, 0x00010000, 2);
Test(-2, 0, 0, 0x00020000, 1);
Test(-2, 0, 0, 0x00020000, 2);
Test(-2, 0, 0, 0x00000000, 3);
Test(0, 1, 0, 0x00000000, 1);
Test(0, 1, 0, 0x00000000, 2);
Test(0, 1, 0, 0x00010000, 1);
Test(0, 1, 0, 0x00010000, 2);
Test(0, 1, 0, 0x00020000, 1);
Test(0, 1, 0, 0x00020000, 2);
Test(-1, 2, 0, 0x00000000, 1);
Test(-1, 2, 0, 0x00000000, 2);
Test(-1, 2, 0, 0x00010000, 1);
Test(-1, 2, 0, 0x00010000, 2);
Test(-1, 2, 0, 0x00020000, 1);
Test(-1, 2, 0, 0x00020000, 2);
Test(-2, 3, 0, 0x00000000, 1);
Test(-2, 3, 0, 0x00000000, 2);
Test(-2, 3, 0, 0x00010000, 1);
Test(-2, 3, 0, 0x00010000, 2);
Test(-2, 3, 0, 0x00020000, 1);
Test(-2, 3, 0, 0x00020000, 2);
Just for Laughs
我在3 Ghz上进行了1000万次迭代的性能测试。英特尔芯片:
我的:11.6 ns
Joe's:32.1 ns
答案 2 :(得分:0)
这个怎么样:
static class DecimalExt {
public static decimal PlusPlus(this decimal value) {
decimal test = 1M;
while (0 != value % test){
test /= 10;
}
return value + test;
}
}
class Program {
public static void Main(params string[] args) {
decimal x = 3.14M;
x = x.PlusPlus(); // now is 3.15
}
}
我在这里使用了扩展方法;你不能重新定义小数类型的++运算符。
答案 3 :(得分:0)
这样可以解决问题:
decimal d = 0.01M;
int incr = 1;
int pos = d.ToString().IndexOf('.');
int len = d.ToString().Length - pos - 1;
if (pos > 0)
{
double val = Convert.ToDouble(d);
val = Math.Round(val * Math.Pow(10, len) + incr) / Math.Pow(10, len);
d = Convert.ToDecimal(val);
}
else
d += incr;
return d;