65.9K
CodeProject 正在变化。 阅读更多。
Home

十进制转英文分数算法

starIconstarIconstarIcon
emptyStarIcon
starIcon
emptyStarIcon

3.60/5 (9投票s)

2005年1月15日

2分钟阅读

viewsIcon

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`则算作一种算法,而分割字符串则不算。

© . All rights reserved.