十进制转英文分数算法






3.60/5 (9投票s)
2005年1月15日
2分钟阅读

88412
一个用MC++编写的四行算法,用于将十进制转换为分数。
引言
一个用MC++编写的四行算法,用于将十进制值转换为三个独立的部分:整数部分、分子、分母。其结果适合于格式化字符串。
公式
基本公式是将小数点右边的值除以分数测量的十进制等值,并四舍五入到整数。这将成为分子除以所需的分母(转换分数的分母)。因此,对于转换为八分之一,因为1/8是0.125,所以将小数的`IEEERmainder()`除以0.125以获得8分之几的分子。
将3.6742转换为16分之一:0.6742/0.0625 = 10.7872。10.7872四舍五入到11,生成分数11/16。结果是三又十六分之十一 (3 11/16)。
将3.6742转换为8分之一:0.6742/0.125 = 5.3936 = 5/8。结果是三又八分之五 (3 5/8)。
我使用`Math::IEERemainder(decimal, 1.0)`来分离小数和`single`值,并使用`Math::floor(decimal)`来分离整数部分。如果小数部分大于0.5,则`Math`算法返回负补码,并且必须从1中减去。因此,这一行
if (Math::Sign(remainder) == -1) remainder = 1 + remainder
0.6742返回-0.32579942,当加上1.0时,结果为0.6742008。
由于对符号的检查,该算法仅适用于正数。
算法
(小数和分母是输入值)
Single remainder = Math::IEEERemainder(decimal, 1.0); if (Math::Sign(remainder) == -1) remainder = 1 + remainder; Int32 units = Convert::ToInt32(Math::Floor(decimal)); Int32 numerator = Convert::ToInt32(Math::Round(remainder/denominator));
其他考虑因素:
为了灵活起见,最好提供一个整数来指定所需的转换,而不是硬编码,例如,将0.125作为分母。因此,输入一个整数分子并计算除数。
// compute the fractions numerator Single divisor = Convert::ToSingle(1)/Convert::ToSingle(denominator); Int32 numerator = Convert::ToInt32(Math::Round(remainder/divisor));
该算法仅适用于正小数,因此需要测试标志、校正并恢复负数。此外,需要考虑的问题包括向下舍入到零和向上舍入到下一个单位,以及分数的约简。以下代码考虑了这些因素。
以下代码是为一个非常具体的用途编写的:转换英制英寸测量分数,特别是常用的分数1/8、1/4和1/2。(虽然我测试到了1/32。)我对1/5、1/7或1/324等分数不感兴趣。该算法可能对那些人有用,但示例函数并非如此。代码不是通用的。但算法是通用的。代码仅作为包装示例提供。
代码
#pragma warning( disable : 4244 ) // possible loss of data due to conversion
// Convert a Single to a string fraction of the
// form "integer numerator/denominator"
String* Utils::Form1::SingleToStringFraction(Single decimal, Int32 denominator)
{
// Input must be positive so save and restore the negative if necessary.
bool isneg = (Math::Sign(decimal) == -1) ? true : false;
if (isneg) decimal *= -1;
// obtain the decimal and units parts of the input number
Single remainder = Math::IEEERemainder(decimal, 1.0);
if (Math::Sign(remainder) == -1) remainder = 1 + remainder;
Int32 units = Convert::ToInt32(Math::Floor(decimal));
// compute the fractions numerator
Single divisor = Convert::ToSingle(1)/Convert::ToSingle(denominator);
Int32 numerator = Convert::ToInt32(Math::Round(remainder/divisor));
String* fraction;
// Handle an error or condition or reduce the fraction
// and convert to a string for the return.
if ((numerator > 0) && (numerator == denominator))
{
// than fraction is one full unit
units++;
fraction = S"";
}
else if (numerator == 0)
{
// as numerator is 0, no fraction
fraction = S"";
}
else
{
// reduce
while (numerator%2 == 0)
{
numerator /= 2;
denominator /= 2;
}
fraction = String::Format(" {0}/{1}",
numerator.ToString(), denominator.ToString());
}
// restore negativity
if (isneg) units *= -1;
#ifdef _DEBUG_CUT
String* rtnstr;
if (isneg) decimal *= -1;
rtnstr = String::Format("{0}{1}", units.ToString(), fraction);
Diagnostics::Trace::WriteLine(rtnstr, decimal.ToString());
#endif
return String::Format("{0}{1}", units.ToString(), fraction);
}
#pragma warning( default : 4244 )
注意事项
我从未声称自己无所不知。而且,我的MC++技能可能有所欠缺。如果您知道更好的、更高效的算法,或者可以改进上述代码的质量,请发表评论。在我的项目中,我将经常在分数和小数之间来回转换。效率会很好。
哦,是的,可以简单地转换为字符串,然后使用split on S“.”;但这有什么乐趣呢?而使用`Math`来分割`Single`则算作一种算法,而分割字符串则不算。