编码挑战:将浮点数转换为具有数字位数限制的分数 [英] Coding challenge: convert a float to a fraction with a set limit on the number of digits

查看:144
本文介绍了编码挑战:将浮点数转换为具有数字位数限制的分数的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

你的老板是老学校。真是老派。他不喜欢这种新的十进制十进制符号,而是希望所有内容都是分数。 1/2。 2/3。 35829分之5647。老学校。



您的挑战是采用浮点值并将其转换为分数。您的回答必然是近似值,并且该近似值的准确性将取决于分母所允许的最大位数。值的任何整个部分都显示在分数之前,并且不包含在字符限制中



函数签名应该是

Your boss is old school. Really old school. He doesn't like this new fangled decimal notation and instead wants everything in fractions. 1/2. 2/3. 5647/35829. Old school.

Your challenge is to take a floating point value and convert it to a fraction. You're answer will be, necessarily, an approximation, and the preciseness of that approximation will depend on the maximum number of digits you're allowed for the denominator. Any whole parts of the value are displayed before the fraction and are not included in character limits

The function signature should be

string FloatToFraction(float inputValue, int denominatorDigits)



所以 FloatToFraction(0.3333,1)=> 1/3 FloatToFraction(100.333333,1)=> 100 1/3



样本输入:



(0.333 ,1)=> 1/3

(0.125,2)=> 10/80或1/8

(0.00205501,6)=> 719/349875


So FloatToFraction(0.3333, 1) => "1/3", FloatToFraction(100.333333, 1) => "100 1/3"

Sample input:

(0.333, 1) => 1/3
(0.125, 2) => 10/80 or 1/8
(0.00205501, 6) => 719/349875

推荐答案

无论我如何尝试构建和销售它,我的思想都坚决拒绝参与其中。我是否赢得奖品?
No matter how I try and frame and sell it, my mind is resolutely refusing to get involved with this. Do I win the prize?


我打算用 Farey序列继续分数,但我已经提交了此解决方案帖子。



在.NET中, float 类型的精度只有七位数(参考)因此转换的精度已经存在上限。但是,如果你真的想卖掉你的浮动空头,你可以给它一个更严格的分母价值。它使用良好的'欧几里德'来生成最低分的分数。此外,由于 float 的范围限制为10 ^ 38,因此输出可以右对齐为漂亮。



I was going to write something that approximated using Farey sequence or continued fractions, but I've already submitted this solution posting.

In .NET, the float type already has a precision of only seven digits (reference) so there's already an upper limit on the precision of the conversion. But, if you really want to sell your float short, you can give it an even more stringent denominator value. It uses good ol' Euclid to generate the fraction in lowest terms. Also, as float is limited in range by 10^38, the output can be right-justified to be "pretty."

using System;

namespace CodingChallenge
{
    public class Program
    {
        public static void Main(string[] args)
        {
            float[] values = { 0.12345F, 1 / 3F, 0.12345678F, 6 };
            foreach (var f in values)
            {
                FloatToFraction fc = new FloatToFraction(f);
                Console.WriteLine(fc);
            }

            // End point
            Console.WriteLine("All done!");
            Console.ReadLine();
        }
    }

    public class FloatToFraction
    {        
        // Is a private property a priverty?
        private readonly float inputValue;
        private readonly int _floatPrecisionLimit;        
        private readonly Func<float,Fraction> _convertToFraction; 

        // ctors and overrides
        public FloatToFraction(float inputValue) : this(inputValue,7){}

        public FloatToFraction(float inputValue, int denominatorDigits)
        {
            this.inputValue = inputValue;
            this._convertToFraction = PrecisionLimitMethod;
            _floatPrecisionLimit = (int) Math.Pow(10,denominatorDigits);
        }

        public override string ToString()
        {
            int leadingDigit = (int)Math.Truncate(inputValue);
            float normalizedValue = inputValue - leadingDigit;

            Fraction f = this._convertToFraction(normalizedValue);

            string A = string.Format("{0,40}", leadingDigit.ToString());
            string B = f.ToString();

            return string.Format(string.Concat(A,B));
        }


        // Lookin' at privates
        private Fraction PrecisionLimitMethod(float normalizedValue)
        {
            int numerator = (int)(normalizedValue * _floatPrecisionLimit);
            int denominator = _floatPrecisionLimit;

            int gcd = FloatToFraction.gcd(numerator, denominator);
            numerator /= gcd;
            denominator /= gcd;

            return new Fraction(numerator, denominator);
        }
        
        private static int gcd(int a, int b)
        {
            if (b == 0)
            {
                return a;
            }
            else
            {
                return gcd(b, a % b);
            }
        }

        private struct Fraction
        {
            public int numerator;
            public int denominator;

            public Fraction(int numerator,int denominator)
            {
                this.numerator = numerator;
                this.denominator = denominator;
            }

            public override string ToString()
            {
                if (numerator == 0)
                    return string.Empty;
                else
                    return string.Format("{0,8} / {1,8}", numerator, denominator);
            }
        }
    }
}


此程序适用于HP Prime计算器

第二个参数是分子和分母的最大值。

当分数的两个部分必须符合8或16位值时,它很有用。

如名称所示,它使用Farey系列。

This program is for a HP Prime calculator
The second parameter is the maximum value of both numerator and denominator.
It is useful when both parts of the fraction must fit 8 or 16 bits values.
As the name indicate, it use Farey series.
#pragma mode( separator(.,;) integer(h64) )
// rev 6030 update

EXPORT FareyMax(Vl, DMax)
// Round a Vl to the best fraction with denominator < DMax
BEGIN
    LOCAL VlE, Tmp;
    LOCAL DbN,DbD, FnN,FnD, RsN,RsD,RsE;
    VlE:= ABS(Vl);
    DbN:= IP(VlE); DbD:=1; FnN:=DbN+1; FnD:=1;
    RsN:= ROUND(VlE,0); RsD:= 1; RsE:= ABS(VlE-(RsN/RsD));
    WHILE DbD+FnD <= DMax AND DbN+FnN <= DMax DO
      Tmp:= (DbN+FnN)/(DbD+FnD);
      IF RsE > ABS(VlE-Tmp) THEN
        RsN:= (DbN+FnN); RsD:= (DbD+FnD); RsE:= ABS(VlE-(RsN/RsD));
      END;
      IF Tmp < VlE THEN
        DbN:= (DbN+FnN); DbD:= (DbD+FnD);
      ELSE
        FnN:= (DbN+FnN); FnD:= (DbD+FnD);
      END;
    END;
    // RETURN "'"+STRING(SIGN(Vl)*RsN,2,0)+"/"+STRING(RsD,2,0)+"'";
    RETURN EXPR("QUOTE("+STRING(SIGN(Vl)*RsN,2,0)+"/"+STRING(RsD,2,0)+")");
END;




FareyMax(0.3333, 9) => 1/3
FareyMax(100.333333, 9) => 301/3
FareyMax(0.125, 99) => 1/8
FareyMax(0.00205501, 999999) => 1829/890020 // Chris I fear your example is wrong.
FareyMax(PI, 500) => 355/113



我喜欢PI的这一部分,很容易记住:


I like this fraction of PI, very easy to remember:

113355, cut in middle 113/355, and swap 355/113


这篇关于编码挑战:将浮点数转换为具有数字位数限制的分数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆