Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/.net/22.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 将十进制数四舍五入到非零的第一个十进制位置_C#_.net_Math_Decimal_Rounding - Fatal编程技术网

C# 将十进制数四舍五入到非零的第一个十进制位置

C# 将十进制数四舍五入到非零的第一个十进制位置,c#,.net,math,decimal,rounding,C#,.net,Math,Decimal,Rounding,我想将一个数字缩短为第一个非0的有效数字。后面的数字应该四舍五入 示例: 0.001 -> 0.001 0.00367 -> 0.004 0.00337 -> 0.003 0.000000564 -> 0.0000006 0.00000432907543029 -> 0.000004 目前我有以下程序: if (value < (decimal) 0.01) { value = Math.Round(value, 4); } if(值

我想将一个数字缩短为第一个非0的有效数字。后面的数字应该四舍五入

示例:

0.001 -> 0.001
0.00367 -> 0.004
0.00337 -> 0.003
0.000000564 -> 0.0000006
0.00000432907543029 ->  0.000004
目前我有以下程序:

if (value < (decimal) 0.01)
{
    value = Math.Round(value, 4);
}
if(值<(十进制)0.01)
{
值=数学四舍五入(值,4);
}
注:

  • 数字永远是正的
  • 有效位数始终为1
  • 大于0.01的值将始终四舍五入到小数点后两位,因此if<0.01

从上面的示例中可以看出,四舍五入到小数点后4位可能不够,值可能会有很大的差异。

我会声明
精度
变量,并使用迭代将该变量乘以
10
与未命中的原始值,
精度
将添加
1

然后使用
precision
变量be
Math.Round
第二个参数

static decimal RoundFirstSignificantDigit(decimal input) {
    int precision = 0;
    var val = input;
    while (Math.Abs(val) < 1)
    {
        val *= 10;
        precision++;
    }
    return Math.Round(input, precision);
}

结果

(-0.001m).RoundFirstSignificantDigit()                  -0.001
(-0.00367m).RoundFirstSignificantDigit()                -0.004
(0.000000564m).RoundFirstSignificantDigit()             0.0000006
(0.00000432907543029m).RoundFirstSignificantDigit()     0.000004
        Console.WriteLine(RoundToFirstNonNullDecimal(0.001m));                0.001
        Console.WriteLine(RoundToFirstNonNullDecimal(0.00367m));              0.004
        Console.WriteLine(RoundToFirstNonNullDecimal(0.000000564m));          0.0000006
        Console.WriteLine(RoundToFirstNonNullDecimal(0.00000432907543029m));  0.000004
        Console.WriteLine(RoundToFirstNonNullDecimal(0.12m));                 0.12
        Console.WriteLine(RoundToFirstNonNullDecimal(1.232m));                1.23
        Console.WriteLine(RoundToFirstNonNullDecimal(7));                     7.00
像这样的

    public decimal SpecialRound(decimal value) 
    {
        int posDot = value.ToString().IndexOf('.'); // Maybe use something about cultural (in Fr it's ",")
        if(posDot == -1)
            return value;

        int posFirstNumber = value.ToString().IndexOfAny(new char[9] {'1', '2', '3', '4', '5', '6', '7', '8', '9'}, posDot);

        return Math.Round(value, posFirstNumber);
    }
另一种方法

    decimal RoundToFirstNonNullDecimal(decimal value)
    {
        var nullDecimals = value.ToString().Split('.').LastOrDefault()?.TakeWhile(c => c == '0').Count();
        var roundTo = nullDecimals.HasValue && nullDecimals >= 1 ? nullDecimals.Value + 1 : 2;
        return Math.Round(value, roundTo);
    }
结果

(-0.001m).RoundFirstSignificantDigit()                  -0.001
(-0.00367m).RoundFirstSignificantDigit()                -0.004
(0.000000564m).RoundFirstSignificantDigit()             0.0000006
(0.00000432907543029m).RoundFirstSignificantDigit()     0.000004
        Console.WriteLine(RoundToFirstNonNullDecimal(0.001m));                0.001
        Console.WriteLine(RoundToFirstNonNullDecimal(0.00367m));              0.004
        Console.WriteLine(RoundToFirstNonNullDecimal(0.000000564m));          0.0000006
        Console.WriteLine(RoundToFirstNonNullDecimal(0.00000432907543029m));  0.000004
        Console.WriteLine(RoundToFirstNonNullDecimal(0.12m));                 0.12
        Console.WriteLine(RoundToFirstNonNullDecimal(1.232m));                1.23
        Console.WriteLine(RoundToFirstNonNullDecimal(7));                     7.00

代码来自
R
,但算法应该是显而易见的

> x = 0.0004932
> y = log10(x)
> z = ceiling(y)
> a = round(10^(y-z),1)
> finally = a*10^(z)
> finally
[1] 5e-04
以下内容基本上已经由Benjamin K提供
冒着被贴上十足怪人标签的风险,我要高兴地宣布,
regexp
是你的朋友。将数字转换为字符字符串,搜索既不是“.”也不是“0”的第一个字符的位置,抓住该位置的字符和后面的下一个字符,将它们转换为数字,舍入,然后(因为您很小心),将结果乘以$10^{(在“.”和第一个数字之间找到的零数)}$

看看这里:@AaronHayman:这是
十进制
而不是
双精度
,有效位数不一定是已知的-例如,我怀疑OP不想将123.456四舍五入到100。(尽管我们将看到…)对于不在-1和1之间的值,您希望执行什么操作?例如,123.456的结果会是什么?我希望使用
GetBits
的解决方案会更快,但是(似乎)尾数不一定是标准化的,这并不比找到尾数的小数位数容易(尽管如此,一些位扫描反向黑客可能会起作用)注意:这可能需要调整负值。Math.Abs(val)@AccessDenied是的,我想只是比较绝对值为什么不使用
Match.Abs(Match.Log10(input))
来获得所需的精度?当前的解决方案存在聚合浮点舍入问题。最好创建一个整数循环变量,然后每次迭代都将该变量乘以10,并将其与原始值相乘。另外,
ByFirstPrecision
是一个可怕的名称-可能类似于
roundfirstimplicantdigit
?您的结果与“大于0.01的值将始终四舍五入到小数点后两位”的标准不匹配。最后两个例子应该是1.23和7.00you's right@GlenYates,出于某种原因,我错过了这个要求,我现在编辑了我的答案。然而,这是一个比公认的解决方案慢得多的解决方案,我也投了更高的票!六羟甲基三聚氰胺六甲醚。。。看起来我是被本杰明K.忍者击倒的。很抱歉。
> x = 0.0004932
> y = log10(x)
> z = ceiling(y)
> a = round(10^(y-z),1)
> finally = a*10^(z)
> finally
[1] 5e-04