C# - Math.Round(double d, 2, MidPointRounding.AwayFromZero) 生成许多小数

问题描述 投票:0回答:1

所以我正在编写一些代码,但我遇到了一个问题!现在,这可能是一个重复的问题,但出于我的爱,我找不到其他人有同样的问题,所以这里是;

我正在尝试将随机生成的双精度舍入到小数点后两位。大多数时候这都按预期工作。然而,每隔一段时间,我的代码会生成最多 10 位小数的双精度数,这确实很烦人,因为这些值显示在 WPF 中的 DataGrid 中,而 DataGrid 只是调整大小以适合数字。我用来生成双打的代码:

double d = rand.NextDouble() + .5; // I have more of these, differing from + .5 to + 2

然后将其四舍五入,我使用:

Math.Round(d, 2, MidPointRounding.AwayFromZero);

大多数时候,它都能完美运行,但时不时地,它会产生如下数字:

0.639999999999999

任何人都可以解释我在这里做错了什么吗? 预先感谢。

编辑1: 所以我并没有完全按照我说的去做。如果这与它不起作用的原因有什么关系,我想知道,但我实际创建双打的方式是;

Math.Round(rand.NextDouble() + .5, 2, MidPointRounding.AwayFromZero);

但是,我不明白为什么它会产生影响,如果先创建一个双精度,然后对其进行舍入,或者如果我只是对新创建的双精度进行 insta 舍入。

编辑2: 根据要求,我发布了我的 DataGrid 代码。 XAML 和代码隐藏如下所示: XAML:

<DataGrid x:Name="marketDataGrid" 
              HorizontalAlignment="Left" 
              Margin="13,225,0,0" 
              VerticalAlignment="Top" 
              Height="204" Width="303" 
              CanUserAddRows="False"
              CanUserDeleteRows="False"
              CanUserReorderColumns="False"
              CanUserResizeColumns="False"
              CanUserResizeRows="False"
              SelectionMode="Extended"
              IsReadOnly="True">
        <DataGrid.Resources>
            <Style TargetType="DataGridRow">
                <EventSetter Event="MouseDoubleClick" Handler="MarketRow_DoubleClick" ></EventSetter>
            </Style>
        </DataGrid.Resources>

双击事件背后的代码:

private void MarketRow_DoubleClick(object sender, RoutedEventArgs e)
    {
        DataGridRow row = sender as DataGridRow;
        Company c = (Company)marketDataGrid.SelectedItem;
        BuyWindow bw = new BuyWindow(c, pc, this);
        bw.Show();
    }

以及我添加对象列表的代码

 marketDataGrid.ItemsSource = cc.GetCList();
 marketDataGrid.Items.Refresh();

如果您需要更多,请告诉我。如果您想查看全部内容,我可以将整个项目上传到某个地方。这样做我可能会有点尴尬,因为我的代码自始至终都不是很漂亮。

这可能是我的错字……但我不这么认为。我已经非常仔细地查看了解决方案。

c# wpf datagrid
1个回答
0
投票

根据

double
的本质,在101个数学值
0.50, 0.51, 0.52, ..., 1.48, 1.49, 1.50
中,只有5(即
0.50
0.75
1.00
1.25
1.50
)可以准确地表示出来。所有其他(
0.51
0.52
等)都将具有与数学上精确的两位十进制值不同的内部表示。

(您可以使用

int
(值从
50
150
)或
decimal
(从
0.50m
1.50m
)来避免这种情况。)

因此,这一切都取决于如何将内部

double
表示形式 格式化 为可显示的数字和分隔符字符串。

您说您使用WPF,但没有提供有关网格中使用的格式的更多信息。我不确定 WPF 是否使用

double.ToString
或其他一些机制。

提出问题时,.NET(当时称为 .NET Core)和 .NET Framework 都使用了不符合 IEEE 标准的

double.ToString
实现。在这种非标准实现下,使用格式字符串
"G17"
在某些情况下可能会揭示部分表示不准确的情况。例如,
(0.51).ToString("G17")
给出字符串
"0.51000000000000001"
(小数点分隔符
.
取决于具有此重载的当前
CultureInfo
)。然而,像
(0.62).ToString("G17")
这样的东西只给出
"0.62"
,因为在这种情况下 17 个有效数字不足以揭示差异。

从 2019 年(.NET Core 3.0)开始,.NET 中的格式与 .NET Framework 中的格式存在显着差异。前者现在使用更合规的算法,而后者仍然使用旧的非标准实现。

在 2019 年之后的 .NET 中,您可以要求比 17 多得多的数字。例如,

(0.51).ToString("G40")
现在给出
"0.5100000000000000088817841970012523233891"
(0.62).ToString("G40")
给出
"0.6199999999999999955591079014993738383055"
。您可以在此处阅读有关这些重大更改的更多信息。有一个指向 Tanner Gooding 的博客文章 .NET Core 3.0 中的浮点解析和格式化改进的链接。

正如我所说,我不确定 2016 年(即 2019 年之前)的 WPF 是否使用了 .NET 的非标准格式化逻辑,或者有自己的格式化逻辑。也许它有自己的。这需要 WPF 专家(不是我)来回答,可能还需要一些有关您的设置的附加信息。

© www.soinside.com 2019 - 2024. All rights reserved.