相关疑难解决方法(0)

在C#中将小数转换为双数会产生差异

问题摘要:

对于某些十进​​制值,当我们将类型从十进制转换为double时,会将一小部分添加到结果中.

更糟糕的是,可能存在两个"相等"的十进制值,这些值在转换时会产生不同的双精度值.

代码示例:

decimal dcm = 8224055000.0000000000m;  // dcm = 8224055000
double dbl = Convert.ToDouble(dcm);    // dbl = 8224055000.000001

decimal dcm2 = Convert.ToDecimal(dbl); // dcm2 = 8224055000
double dbl2 = Convert.ToDouble(dcm2);  // dbl2 = 8224055000.0

decimal deltaDcm = dcm2 - dcm;         // deltaDcm = 0
double deltaDbl = dbl2 - dbl;          // deltaDbl = -0.00000095367431640625
Run Code Online (Sandbox Code Playgroud)

查看评论中的结果.结果从调试器的手表中复制.产生这种效果的数字的十进制数字远远少于数据类型的限制,所以它不能是溢出(我猜!).

更有趣的是,可以有两个相等的十进制值(在上面的代码示例中,参见"dcm"和"dcm2","deltaDcm"等于零),在转换时产生不同的双精度值.(在代码中,"dbl"和"dbl2",它们具有非零"deltaDbl")

我想它应该是与两种数据类型中数字的按位表示的差异相关的东西,但是无法弄清楚是什么!而且我需要知道如何按照我需要的方式进行转换.(比如dcm2 - > dbl2)

c# double decimal

43
推荐指数
3
解决办法
4万
查看次数

.NET的Double.ToString方法中的Round-two错误

在数学上,考虑这个问题的有理数

8725724278030350 / 2**48
Run Code Online (Sandbox Code Playgroud)

其中**在分母表示取幂,即,分母是248次方.(分数不在最低方面,通过2可还原的)此数目是恰好作为表示的System.Double.它的十进制扩展是

31.0000000000000'49'73799150320701301097869873046875 (exact)
Run Code Online (Sandbox Code Playgroud)

撇号不代表缺失的数字,而只是标记圆形到15的分数.将执行17位数字.

请注意以下内容:如果此数字四舍五入为15位,则结果为31(后跟十三0秒),因为下一个数字(49...)以a开头4(意味着向下舍入).但如果数字首先四舍五入为17位,然后四舍五入为15位,结果可能是31.0000000000001.这是因为第一次舍入通过将49...数字增加到50 (terminates)(下一个数字73...)而向上舍入,然后第二次舍入可能再次向上舍入(当中点舍入规则表示"从零开始舍入"时).

(当然,还有更多具有上述特征的数字.)

现在,事实证明.NET的这个数字的标准字符串表示是"31.0000000000001".问题:这不是一个错误吗?通过标准字符串表示,我们指的String是由参数Double.ToString()实例方法产生的,当然,该方法与生成的方法相同ToString("G").

需要注意的一个有趣的事情是,如果你投的上述号码System.Decimal,然后你得到一个decimal31准确!请参阅此Stack Overflow问题,以讨论将a转换DoubleDecimal包含第一个舍入到15位的令人惊讶的事实.这意味着转换为Decimal正确的舍入到15位数,而调用ToSting()是不正确的.

总而言之,我们有一个浮点数,当输出给用户时,是31.0000000000001,但当转换为Decimal …

.net c# floating-point rounding

15
推荐指数
2
解决办法
1965
查看次数

C#中双重比较精度损失,加减减双精度时发生精度损失

刚开始学习C#.我计划将它用于繁重的数学模拟,包括数值求解.问题是我在添加和减去double时以及比较时都会出现精度损失.代码及其返回的内容(在评论中)如下:

namespace ex3
{
    class Program
    {
        static void Main(string[] args)
        {

            double x = 1e-20, foo = 4.0;

            Console.WriteLine((x + foo)); // prints 4
            Console.WriteLine((x - foo)); // prints -4
            Console.WriteLine((x + foo)==foo); // prints True BUT THIS IS FALSE!!!
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

非常感谢任何帮助和澄清!

令我困惑的是(x + foo)==foo回报True.

c# precision double

5
推荐指数
1
解决办法
822
查看次数

Double.ToString()的奇怪行为

我试图将double值9007199254740992.0转换为字符串.

但似乎存在舍入错误(最后2个变为0):

(9007199254740992.0).ToString("#")    // Returns "9007199254740990"
(9007199254740992.0).ToString()       // Returns"9.00719925474099E+15"
Run Code Online (Sandbox Code Playgroud)

首先,我认为这个数字可能无法表示为双数.但它可以.这可以通过将其转换为long然后将其转换为字符串来看出.

((long)9007199254740991.0).ToString() // Returns "9007199254740991"
((long)9007199254740992.0).ToString() // Returns "9007199254740992"
Run Code Online (Sandbox Code Playgroud)

另外,我发现如果我使用"R"格式,它可以工作.

(9007199254740992.0).ToString("R")    // Returns "9007199254740992"
Run Code Online (Sandbox Code Playgroud)

任何人都可以解释为什么ToString("#")不以完整精度返回整数部分的双精度?

c# double

3
推荐指数
1
解决办法
564
查看次数

哪个C#double literal不能完全表示为double?

维基百科说:

例如,十进制数0.1不能以任何有限精度的二进制浮点表示

但是,在C#中

string s = 0.1.ToString(CultureInfo.InvariantCulture);
Console.WriteLine(s);
Run Code Online (Sandbox Code Playgroud)

写道0.1.

我本以期待某事0.099999999999999999.

我正在寻找至少一个双精简版的例子,它不能完全代表双精度.

编辑:

正如其他人所指出的,0.1确实是我一直在寻找的文字,正如下面的经典代码示例所示:

double sum = 0.0;

for (int i = 0; i < 10; i++)
{
    sum += 0.1;
}

Console.WriteLine(sum.Equals(1.0)); // false
Run Code Online (Sandbox Code Playgroud)

当双精度转换为其他数据类型时,会发生奇怪的事情.这不仅仅是string因为这个表达式是真的:0.1m.Equals((decimal)0.1)

c# double literals

2
推荐指数
1
解决办法
533
查看次数

如何使用 Utf8JsonWriter 在“.0”完好无损的情况下编写像“82.0”这样的浮点数?

我一直在努力编写一个 double,例如82.0使用 Utf8JsonWriter。

默认情况下,methodWriteNumberValue方法接受一个 double 并为我格式化它,并且格式(这是标准的“G”格式)省略了“.0”后缀。我找不到控制它的方法。

按照设计,我似乎不能只将原始字符串写入 Utf8JsonWriter,但我找到了一种解决方法:创建一个 JsonElement 并调用 JsonElement.WriteTo`。这会调用Utf8JsonWriter 中私有方法并将字符串直接写入其中。

有了这个发现,我做出了一个非常笨拙且效率低下的实现。

open System.Text.Json

void writeFloat(Utf8JsonWriter w, double d) {
  String floatStr = f.ToString("0.0################")
  JsonElement jse = JsonDocument.Parse(floatStr).RootElement
  jse.WriteTo(w)
}
Run Code Online (Sandbox Code Playgroud)

无论如何我都需要格式化一个double,这样很好,但是解析它,创建一个jsonDocument和一个JsonElement,只是为了能够找到一种调用受保护方法的方法,似乎真的很浪费。但是,它确实有效(我用 F# 编写并转换为 C#,如果我在语法中犯了错误,请道歉)。

有没有更好的办法?想到的一些潜在解决方案(我是 dotnet 的新手,所以我不确定这里有什么可能):

  • 有没有办法直接访问私有API?我认为子类化 Utf8Writer 可能会起作用,但它是一个密封类。
  • 我可以直接实例化一个 JsonElement 而不用整个解析繁琐吗?

至于为什么这是必要的:我需要强制写入整数值,.0因为我需要与之交互的非常具体的格式,它区分整数和浮点 JSON 值。(我对指数格式没意见,因为这显然是一个浮点数)。

.net c# system.text.json

1
推荐指数
1
解决办法
281
查看次数