首页 > 解决方案 > 如何在 C# 中表示像 1/3 这样的分数?

问题描述

我正在编写一个食谱应用程序,该应用程序需要对成分执行加法/减法以制作主购物清单。我想不通的是如何以不会导致 .9999999 .... 而不是 1 的方式表示 1/3 之类的分数(不会转换为干净的小数)。我可以'甚至不能使用盎司作为基本单位,因为三分之一杯是 2.6666666 盎司。

简而言之,这个想法是,如果用户正在制作使用糖的食谱,他们可能会有一个要求一杯,另一个要求半杯,另一个要求三分之一杯。然后,这将告诉他们在下次购物之旅中需要获得 1 5/6 杯糖。

有没有人解决这个问题,或者我应该禁止所有带有丑陋分数的食谱(这远非理想)?

到目前为止,我想出的最接近的方法是将每种成分存储为三分之一盎司的倍数,但这使得后端逻辑有点复杂!

如果修复将允许我轻松地将值存储在 Postgres 数据库中,则可以加分!

标签: c#asp.netpostgresqlasp.net-core.net-core

解决方案


我认为您最好将分数的现有实现结合起来,例如Fractions NuGet 包Fraction中的类型与一个单元,这将是一个枚举。就像是

struct Amount
{
    public Amount(Fraction quantity, Unit unit)
    {
        Quantity = quantity;
        Unit = unit;
    }

    public Fraction Quantity { get; }
    public Unit Unit { get; }

    ...
}

public enum Unit { Ounce, Cup, Gram, ... };

这使您可以在不同的单位(如杯子/盎司)之间进行转换,但我会在其中添加一些关于舍入的规则,以便您仍然可以使用合理的分数。因为你在谈论食谱,所以这似乎是一个合理的限制,因为如果你少了一点,它不会对食谱有太大的影响(希望如此)!调味!

转换将隐藏在运算符后面;你会超载+,=等。

对于存储,您需要 3 列:分子、分母和单位。这实现了从 DB 到 C# 的 1:1 映射。

您甚至可以按照@Cleptus 在评论中的建议创建用户定义的数据类型,这将保持 1:1 映射。正如@Jeremy 在评论中所说,这种方法有一个缺点:缺乏对平均值等聚合的支持。如果您不需要担心这一点(例如相关食谱的平均糖用量),那么这不是问题。

是的,你可以自己做所有的数学运算,甚至封装它,但我认为自然表示会更易于维护,并且可以很好地从客户端映射到服务器,再到存储。

最后,因为涉及到舍入,所以应该在最后一刻进行以减少误差累积,尤其是在执行求和、平均等聚合函数时。


推荐阅读