将Double格式化为分数

时间:2008-12-18 20:39:37

标签: java string formatting

是否有一个库可以将Double转换为具有整数的String,后跟一个分数?

例如

1.125 = 1 1/8

我只是寻找到64英寸的分数。

10 个答案:

答案 0 :(得分: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);
}

奖金:Code Golf

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);
}

答案 1 :(得分:5)

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

有一点要指出的是,因为你使用的是英寸,如果这些值都是一英寸的合适分数,分母为2,4,8,16,32,64,则该值不应包含浮点错误,因为分母总是2的幂。但是如果你的数据集的值为.1英寸,那么你就会遇到问题。

答案 2 :(得分:4)

org.apache.commons.math怎么样?他们有一个Fraction类需要加倍。

http://commons.apache.org/math/api-1.2/org/apache/commons/math/fraction/Fraction.html

您应该能够扩展它并为第64个功能提供功能。而且你还可以添加一个toString,它可以轻松地为你打印出整数部分。

  

分数(double value,int   maxDenominator)创建一个分数   给出双倍值和最大值   分母。

答案 3 :(得分:3)

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

浮点数可能足够精确,可以毫无损失地正确转换为阵营。

由于大多数使用英寸的人使用2的幂的分母,所以应该没问题。

但回到最初的问题,我不知道会有任何图书馆会这样做。

答案 4 :(得分:1)

以下称为LPC的C变体的功能如下所示。一些说明:

  1. 在开始时添加输入值是为了尝试处理精确问题,否则最终会告诉您5是4 999999/1000000。
  2. to_int()函数截断为整数。
  3. 语言有一个to_string(),它会将一些浮点数转换为指数表示法。

  4. 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;
    }
    

答案 5 :(得分:1)

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

//How to "Convert" double to fraction("a/b") - kevinlopez@unitec.edu
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;
}

答案 6 :(得分: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();
    }

答案 7 :(得分:0)

正如其他几个人所说的那样,64分的分数可以由IEEE浮点数精确地表示。这意味着我们也可以通过移动和屏蔽位来转换为分数。

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

简要说明:浮点数存储为(符号)(exp)(frac),其中符号为1位,exp为11位,frac为小数部分(1之后),为52位。这是作为数字输入的:

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

因此,我们可以通过移动符合指数的点并在该点之后屏蔽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);
}

(这段代码可能会缩短,但是阅读像这样的位翻码代码很难,因为它......)

答案 8 :(得分: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)

答案 9 :(得分:-1)

为了解决这个问题(在我的一个项目中),我采取了以下步骤:

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