C# 你能发现我的标记助手方法中的数学错误吗?

C# 你能发现我的标记助手方法中的数学错误吗?,c#,math,C#,Math,我已经制作了一个标记帮助器,用于渲染0到5颗星的星级,包括半颗星 这是标记,呈现五颗星: <star-rating rating="10"></star-rating> 但是我的方法有一个我找不到的数学错误。该方法生成以下输出(()=一颗星,(=半颗星): 这里有一个明显的模式,原因是什么 更新 我找到了一个丑陋的解决办法: double dec = stars - Math.Truncate(stars); if (dec == 0.5) { for (int

我已经制作了一个标记帮助器,用于渲染0到5颗星的星级,包括半颗星

这是标记,呈现五颗星:

<star-rating rating="10"></star-rating>
但是我的方法有一个我找不到的数学错误。该方法生成以下输出(
()
=一颗星,
=半颗星):

这里有一个明显的模式,原因是什么

更新

我找到了一个丑陋的解决办法:

double dec = stars - Math.Truncate(stars);
if (dec == 0.5)
{
    for (int s = 1; s < stars; s++)
    {
        sb.AppendFormat("<span class='fas fa-star text-warning text-outline'></span>");
    }
    sb.AppendFormat("<span class='fas fa-star-half'></span>");
}
else
{
    for (int s = 0; s < stars; s++)
    {
        sb.AppendFormat("<span class='fas fa-star'></span>");
    }
}
double dec=stars-数学截断(stars);
如果(dec==0.5)
{
对于(int s=1;s

如果有一个半星,它运行一个for循环,如果没有,它运行另一个for循环,违反了干燥原则…

在for循环中,你将上升到
s
这意味着
0.5
它将创建一个全星,因为它大于
0
。你可以
忽略
Floor
这个
stars
小数点,例如
数学下限(1.5)=1
,这是一个可能的修正,见下文

for (int s = 0; s < Math.Floor(stars); s++)
{
    sb.AppendFormat("<span class='fas fa-star'></span>");
}
for(int s=0;s
编辑:


Math.Truncate()
也可以。

首先,我建议在此处使用
十进制
类型,而不是
双精度
,因为使用
双精度
进行数学运算(然后对结果进行比较)时,可能会出现舍入错误。您会得到“幸运”在您的案例中,因为您使用的是<代码> 5 ,它似乎不存在这个问题,但是,例如,考虑您的代码行:

double dec = stars - Math.Truncate(stars);
如果
stars
2.4
,那么
dec
将是
0.3999999991

如果
stars
2.6
,那么
dec
将是
0.6000000000000009

如果您随后进行比较,则这两种情况都不会给出预期的输出:
if(dec==0.4)
if(dec==0.6)
。因此,一般来说,如果您要对数字进行数学运算并对结果进行比较,使用
decimal
是一个好习惯


要解决问题中的问题,您可以使用以下几个技巧:

  • decimal
    转换为
    int
    以获得整数部分
    • (int)2.5M==2
  • 使用带
    1的模运算符(返回一个数除以另一个数的余数)获取小数部分
    
    • 250万%1==0.5
  • 例如:

    // Loop from .5 to 10 in increments of .5 (the 'M' signifies that the number is a decimal)
    for (decimal i = .5M; i <= 5; i += .5M)
    {
        Console.Write($"{i:0.0}: ");
    
        // First write out our "whole" stars
        for (int j = 0; j < (int) i; j++)
        {
            Console.Write("()");
        }
    
        // Then, if needed, write out the "half" star
        if (i % 1 >= .5M) Console.Write("(");
    
        Console.WriteLine();
    }
    
    GetKeyFromUser("\n\nDone! Press any key to exit...");
    
    //以.5为增量从.5循环到10(“M”表示数字是十进制的)
    对于(十进制i=0.5M;i=0.5M)控制台;
    Console.WriteLine();
    }
    GetKeyFromUser(“\n\n完成!按任意键退出…”);
    
    输出


    for(int s=0;s<0.5;s++)
    此循环一次,而不是零次。稍后使用时,
    s
    将用作测试。在这种情况下,您很幸运,但一般来说,将一个双精度值与另一个相等值(=0.5)进行比较从来都不是一个好主意,如果可以的话,最好使用整数。例如,您可以使用一个int并检查为(int s=0;s<(int)stars;s++)添加半星
    (评级&1==1)
    强制转换为
    int
    也可以。啊..谢谢!我可能太累了,无法直接思考。现在是凌晨2:38…或者存储
    数学。截断
    会产生一个双变量,用作循环边界,稍后用作减法变量。
    
    double dec = stars - Math.Truncate(stars);
    
    // Loop from .5 to 10 in increments of .5 (the 'M' signifies that the number is a decimal)
    for (decimal i = .5M; i <= 5; i += .5M)
    {
        Console.Write($"{i:0.0}: ");
    
        // First write out our "whole" stars
        for (int j = 0; j < (int) i; j++)
        {
            Console.Write("()");
        }
    
        // Then, if needed, write out the "half" star
        if (i % 1 >= .5M) Console.Write("(");
    
        Console.WriteLine();
    }
    
    GetKeyFromUser("\n\nDone! Press any key to exit...");