2008-12-18 48 views
7

是否有一个库将整数转换成一个字符串到一个字符串,然后是一个分数?格式双作为分数

例如

1.125 = 1 1/8 

我只想找分数一英寸的1/64。

回答

5

您可能遇到的一个问题是,并非所有的小数值都可以用双打来表示。甚至一些看起来很简单的值,比如0.1。现在使用伪代码算法。您可能最好确定一英寸的第64个数,但将小数部分除以0.015625。之后,您可以将分数降至最低公分母。但是,由于您声明的是英寸,因此您可能不想使用最小公分母,而只使用英寸通常表示的值,2,4,8,16,32,64。

然而,有一点需要指出的是,由于您使用的是英寸,如果这些值都是一英寸的合适分数,并且分母为2,4,8,16,32,64,则该值永远不会包含浮点错误,因为分母总是2的幂。然而,如果你的数据集中有0.1英寸的值,那么你将开始遇到问题。

+0

数据进来好(总是在一英寸的64ths) – Milhous 2008-12-18 20:51:53

3

我不一定同意,基于Milhous希望覆盖英寸高达1/64的事实“假设程序始终要求1/64”的精度,那应该占用6位的尾数。在一个浮点数中,有24-6 = 18,(如果我的数学正确的话)应该表示他有一个+/- 262144 + 63/64的范围“

这可能足够精确地浮动到正确转换成派系没有损失。

而且,因为大多数人在工作英寸的采用2的幂的分母,它应该是罚款。

但是,回到原来的问题,我不知道任何库,

1

在一个名为LPC的C变体中的函数如下所示:注意:

  1. 在开始时增加输入值是为了解决精度问题,否则它们很容易告诉你5是4 999999/1000000。
  2. to_int()函数截断为整数。
  3. 语言有一个to_string()会将一些浮点数转换为指数表示法。

string strfrac(float frac) { 
    int main = to_int(frac + frac/1000000.0); 
    string out = to_string(main); 
    float rem = frac - to_float(main); 
    string rep; 
    if(rem > 0 && (to_int(rep = to_string(rem)) || member(rep, 'e') == Null)) { 
     int array primes = ({ 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47 }); 
     string base; 
     int exp; 
     int num; 
     int div; 
     if(sscanf(rep, "%se%d", base, exp) == 2) { 
      num = to_int(replace(base, ".", "")); 
      div = to_int(pow(10, abs(exp))); 
     } else { 
      rep = rep[2..]; 
      num = to_int(rep); 
      div = to_int(pow(10, strlen(rep))); 
     } 
     foreach(int prime : primes) { 
      if(prime > num) 
       break; 
      while((num/prime) * prime == num && (div/prime) * prime == div) { 
       num /= prime; 
       div /= prime; 
      } 
     } 
     out += " " + num + "/" + div; 
    } 
    return out; 
} 
10

你的问题很简单,因为你放心分母将始终在C#中除以64,(有人随意翻译一个Java版本):

string ToMixedFraction(decimal x) 
{ 
    int whole = (int) x; 
    int denominator = 64; 
    int numerator = (int)((x - whole) * denominator); 

    if (numerator == 0) 
    { 
     return whole.ToString(); 
    } 
    while (numerator % 2 == 0) // simplify fraction 
    { 
     numerator /= 2; 
     denominator /=2; 
    } 
    return string.Format("{0} {1}/{2}", whole, numerator, denominator); 
} 

奖励:代码高尔夫

public static string ToMixedFraction(decimal x) { 
    int w = (int)x, 
     n = (int)(x * 64) % 64, 
     a = n & -n; 
    return w + (n == 0 ? "" : " " + n/a + "/" + 64/a); 
} 
+0

注意检查甚至岬分母是不必要的。查看我的Java版本。 – erickson 2008-12-18 21:43:28

+0

egads,你是对的:) – Jimmy 2008-12-18 21:53:28

0

我的代码看起来像这样。

public static int gcd(int a, int b) 
    { 
     if (b == 0) 
      return a; 
     else 
      return gcd(b, a % b); 
    } 

public static String doubleToStringFraction(Double d) 
    { 
     StringBuffer result = new StringBuffer(" " + ((int) Math.floor(d))); 
     int whole = (int) ((d - Math.floor(d)) * 10000); 
     int gcd = gcd(whole, 10000); 
     result.append(" " + (whole/gcd) + "/" + 10000/gcd + " "); 
     return result.toString(); 
    } 
-1

为了解决这个问题(在我的项目之一),我采取了以下措施:

  • 内置的十进制/部分字符串的字典。
  • 写了一个函数,根据数字的“十进制”部分和匹配条件搜索字典中最接近的匹配分数。
0

正如其他几个人已经指出的那样,可以用IEEE浮点数来精确地表示64的小数部分。这意味着我们也可以通过移动和屏蔽位来转换成分数。

这里不是解释浮点表示的所有细节的地方,详情请参考wikipedia

简而言之:浮点数存储为(sign)(exp)(frac)其中sign是1位,exp是11位,frac是小数部分(在1之后)并且是52位。这是enterpreted的数量:

(sign == 1 ? -1 : 1) * 1.(frac) * 2^(exp-1023) 

因此,我们可以通过点accoring移动到指数和点后屏蔽掉6位获得第64。在Java:

private static final long MANTISSA_FRAC_BITMAP = 0xfffffffffffffl; 
private static final long MANTISSA_IMPLICIT_PREFIX = 0x10000000000000l; 
private static final long DENOM_BITMAP = 0x3f; // 1/64 
private static final long DENOM_LEN = 6; 
private static final int FRAC_LEN = 52; 

public String floatAsFrac64(double d) { 
    long bitmap = Double.doubleToLongBits(d); 
    long mantissa = bitmap & MANTISSA_FRAC_BITMAP | MANTISSA_IMPLICIT_PREFIX; 
    long exponent = ((bitmap >> FRAC_LEN) & 0x7ff) - 1023; 
    boolean negative = (bitmap & (1l << 63)) > 0; 

    // algorithm: 
    // d is stored as SE(11)F(52), implicit "1." before F 
    // move point to the right <exponent> bits to the right: 
    if(exponent > FRAC_LEN) System.out.println("warning: loosing precision, too high exponent"); 
    int pointPlace = FRAC_LEN-(int)exponent; 
    // get the whole part as the number left of the point: 
    long whole = mantissa >> pointPlace; 
    // get the frac part as the 6 first bits right of the point: 
    long frac = (mantissa >> (pointPlace-DENOM_LEN)) & DENOM_BITMAP; 
    // if the last operation shifted 1s out to the right, we lost precision, check with 
    // if any of these bits are set: 
    if((mantissa & ((MANTISSA_FRAC_BITMAP | MANTISSA_IMPLICIT_PREFIX) >> (pointPlace - DENOM_LEN))) > 0) { 
     System.out.println("warning: precision of input is smaller than 1/64"); 
    } 
    if(frac == 0) return String.format("%d", whole); 
    int denom = 64; 
    // test last bit, divide nom and demon by 1 if not 1 
    while((frac & 1) == 0) { 
     frac = frac >> 1; 
     denom = denom >> 1; 
    } 
    return String.format("%d %d/%d", whole, frac, denom); 
} 

(此代码大概可以缩短,但看完位翻盖这样的代码就足够了,因为它是硬...)

1

我写了这为我的项目,我希望它可能是有用的:

//How to "Convert" double to fraction("a/b") - [email protected] 
private boolean isInt(double number){ 
    if(number%2==0 ||(number+1)%2==0){ 
     return true; 
    } 
    return false; 
} 
private String doubleToFraction(double doub){ 
    //we get the whole part 
    int whole = (int)doub; 
    //we get the rest 
    double rest = doub - (double)whole; 
    int numerator=1,denominator=1; 
    //if the whole part of the number is greater than 0 
    //we'll try to transform the rest of the number to an Integer 
    //by multiplying the number until it become an integer 
    if(whole >=1){ 
     for(int i = 2; ; i++){ 
      /*when we find the "Integer" number(it'll be the numerator) 
      * we also found the denominator(i,which is the number that transforms the number to integer) 
      * For example if we have the number = 2.5 when it is multiplied by 2 
      * now it's 5 and it's integer, now we have the numerator(the number (2.5)*i(2) = 5) 
      * and the denominator i = 2 
      */ 
      if(isInt(rest*(double)i)){ 
       numerator = (int)(rest*(double)i); 
       denominator = i; 
       break; 
      } 
      if(i>10000){ 
       //if i is greater than 10000 it's posible that the number is irrational 
       //and it can't be represented as a fractional number 
       return doub+""; 
      } 
     } 
     //if we have the number 3.5 the whole part is 3 then we have the rest represented in fraction 0.5 = 1/2 
     //so we have a mixed fraction 3+1/2 = 7/2 
     numerator = (whole*denominator)+numerator; 
    }else{ 
     //If not we'll try to transform the original number to an integer 
     //with the same process 
     for(int i = 2; ; i++){ 
      if(isInt(doub*(double)i)){ 
       numerator = (int)(doub*(double)i); 
       denominator = i; 
       break; 
      } 
      if(i>10000){ 
       return doub+""; 
      } 
     } 
    } 
    return numerator+"/"+denominator; 
} 
0

我创建了简单的Fraction库。

库,请访问:https://github.com/adamjak/Fractions

例子:

String s = "1.125"; 
Fraction f1 = Fraction.tryParse(s); 
f1.toString(); // return 9/8 

Double d = 2.58; 
Fraction f2 = Fraction.createFraction(d); 
f2.divide(f1).toString() // return 172/75 (2.29)