c# - 如何在 C# 中表示像 1/3 这样的分数?
问题描述
我正在编写一个食谱应用程序,该应用程序需要对成分执行加法/减法以制作主购物清单。我想不通的是如何以不会导致 .9999999 .... 而不是 1 的方式表示 1/3 之类的分数(不会转换为干净的小数)。我可以'甚至不能使用盎司作为基本单位,因为三分之一杯是 2.6666666 盎司。
简而言之,这个想法是,如果用户正在制作使用糖的食谱,他们可能会有一个要求一杯,另一个要求半杯,另一个要求三分之一杯。然后,这将告诉他们在下次购物之旅中需要获得 1 5/6 杯糖。
有没有人解决这个问题,或者我应该禁止所有带有丑陋分数的食谱(这远非理想)?
到目前为止,我想出的最接近的方法是将每种成分存储为三分之一盎司的倍数,但这使得后端逻辑有点复杂!
如果修复将允许我轻松地将值存储在 Postgres 数据库中,则可以加分!
解决方案
我认为您最好将分数的现有实现结合起来,例如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 在评论中所说,这种方法有一个缺点:缺乏对平均值等聚合的支持。如果您不需要担心这一点(例如相关食谱的平均糖用量),那么这不是问题。
是的,你可以自己做所有的数学运算,甚至封装它,但我认为自然表示会更易于维护,并且可以很好地从客户端映射到服务器,再到存储。
最后,因为涉及到舍入,所以应该在最后一刻进行以减少误差累积,尤其是在执行求和、平均等聚合函数时。