변환하는 방법을 읽을 수 있는 분수가?
-
01-07-2019 - |
문제
이제 우리는 0.33,우리는 우리를 출력해야"1/3".
가 있는 경우에 우리는"0.4",우리는 우리를 출력해야"2/5".
아이디어는 그것이 인간을 읽을 수 있는 사용자가 이해하"x 부품의 y 으로"더 나은 이해의 방법이다.
내가 알고 있는 비율은 좋은 대체 궁금하지만 있다면 간단한 방법으로 하면 이렇게 할 수 있습니까?
해결책
나는 다윗의 엡프스테인 을 찾을 합리적인 근사치하여 주어진 실제 번호 C 코드를 정확히 무엇을 요청한다.그의 이론을 바탕으로 계속 분수와 매우 빠르고 매우 컴팩트합니다.
내가 사용한 버전이 사용자를 위한 특정 분자와 분모한다.
/*
** find rational approximation to given real number
** David Eppstein / UC Irvine / 8 Aug 1993
**
** With corrections from Arno Formella, May 2008
**
** usage: a.out r d
** r is real number to approx
** d is the maximum denominator allowed
**
** based on the theory of continued fractions
** if x = a1 + 1/(a2 + 1/(a3 + 1/(a4 + ...)))
** then best approximation is found by truncating this series
** (with some adjustments in the last term).
**
** Note the fraction can be recovered as the first column of the matrix
** ( a1 1 ) ( a2 1 ) ( a3 1 ) ...
** ( 1 0 ) ( 1 0 ) ( 1 0 )
** Instead of keeping the sequence of continued fraction terms,
** we just keep the last partial product of these matrices.
*/
#include <stdio.h>
main(ac, av)
int ac;
char ** av;
{
double atof();
int atoi();
void exit();
long m[2][2];
double x, startx;
long maxden;
long ai;
/* read command line arguments */
if (ac != 3) {
fprintf(stderr, "usage: %s r d\n",av[0]); // AF: argument missing
exit(1);
}
startx = x = atof(av[1]);
maxden = atoi(av[2]);
/* initialize matrix */
m[0][0] = m[1][1] = 1;
m[0][1] = m[1][0] = 0;
/* loop finding terms until denom gets too big */
while (m[1][0] * ( ai = (long)x ) + m[1][1] <= maxden) {
long t;
t = m[0][0] * ai + m[0][1];
m[0][1] = m[0][0];
m[0][0] = t;
t = m[1][0] * ai + m[1][1];
m[1][1] = m[1][0];
m[1][0] = t;
if(x==(double)ai) break; // AF: division by zero
x = 1/(x - (double) ai);
if(x>(double)0x7FFFFFFF) break; // AF: representation failure
}
/* now remaining x is between 0 and 1/ai */
/* approx as either 0 or 1/m where m is max that will fit in maxden */
/* first try zero */
printf("%ld/%ld, error = %e\n", m[0][0], m[1][0],
startx - ((double) m[0][0] / (double) m[1][0]));
/* now try other possibility */
ai = (maxden - m[1][1]) / m[1][0];
m[0][0] = m[0][0] * ai + m[0][1];
m[1][0] = m[1][0] * ai + m[1][1];
printf("%ld/%ld, error = %e\n", m[0][0], m[1][0],
startx - ((double) m[0][0] / (double) m[1][0]));
}
다른 팁
Python2.6 에 있는 fractions
모듈입니다.
(에서 인용한다)
>>> from fractions import Fraction
>>> Fraction('3.1415926535897932').limit_denominator(1000)
Fraction(355, 113)
>>> from math import pi, cos
>>> Fraction.from_float(cos(pi/3))
Fraction(4503599627370497, 9007199254740992)
>>> Fraction.from_float(cos(pi/3)).limit_denominator()
Fraction(1, 2)
면 출력을 제공하는 인간의 리더 빠른 느낌의 순서의 결과,그것은 아무 의미가 없고 다음과 같은 상태로 되돌아"113/211",그렇게 출력해야한 자신을 사용하여 한 자리 숫자(어쩌면 1/10 및 9/10).그렇다면,당신은 관찰할 수 있는 거기에 만 27 다른 하나입니다.
이후 근본적인 수학을 생성하는 출력 변경되지 않는 솔루션이 될 수 있는 단순히 하드 바이너리 코드 검색 트리,그래서 그 기능을 수행하는 대부분에서 로그(27)~=4 3/4 비교할 수 있습니다.여기에서 테스트되 C 버전의 코드
char *userTextForDouble(double d, char *rval)
{
if (d == 0.0)
return "0";
// TODO: negative numbers:if (d < 0.0)...
if (d >= 1.0)
sprintf(rval, "%.0f ", floor(d));
d = d-floor(d); // now only the fractional part is left
if (d == 0.0)
return rval;
if( d < 0.47 )
{
if( d < 0.25 )
{
if( d < 0.16 )
{
if( d < 0.12 ) // Note: fixed from .13
{
if( d < 0.11 )
strcat(rval, "1/10"); // .1
else
strcat(rval, "1/9"); // .1111....
}
else // d >= .12
{
if( d < 0.14 )
strcat(rval, "1/8"); // .125
else
strcat(rval, "1/7"); // .1428...
}
}
else // d >= .16
{
if( d < 0.19 )
{
strcat(rval, "1/6"); // .1666...
}
else // d > .19
{
if( d < 0.22 )
strcat(rval, "1/5"); // .2
else
strcat(rval, "2/9"); // .2222...
}
}
}
else // d >= .25
{
if( d < 0.37 ) // Note: fixed from .38
{
if( d < 0.28 ) // Note: fixed from .29
{
strcat(rval, "1/4"); // .25
}
else // d >=.28
{
if( d < 0.31 )
strcat(rval, "2/7"); // .2857...
else
strcat(rval, "1/3"); // .3333...
}
}
else // d >= .37
{
if( d < 0.42 ) // Note: fixed from .43
{
if( d < 0.40 )
strcat(rval, "3/8"); // .375
else
strcat(rval, "2/5"); // .4
}
else // d >= .42
{
if( d < 0.44 )
strcat(rval, "3/7"); // .4285...
else
strcat(rval, "4/9"); // .4444...
}
}
}
}
else
{
if( d < 0.71 )
{
if( d < 0.60 )
{
if( d < 0.55 ) // Note: fixed from .56
{
strcat(rval, "1/2"); // .5
}
else // d >= .55
{
if( d < 0.57 )
strcat(rval, "5/9"); // .5555...
else
strcat(rval, "4/7"); // .5714
}
}
else // d >= .6
{
if( d < 0.62 ) // Note: Fixed from .63
{
strcat(rval, "3/5"); // .6
}
else // d >= .62
{
if( d < 0.66 )
strcat(rval, "5/8"); // .625
else
strcat(rval, "2/3"); // .6666...
}
}
}
else
{
if( d < 0.80 )
{
if( d < 0.74 )
{
strcat(rval, "5/7"); // .7142...
}
else // d >= .74
{
if(d < 0.77 ) // Note: fixed from .78
strcat(rval, "3/4"); // .75
else
strcat(rval, "7/9"); // .7777...
}
}
else // d >= .8
{
if( d < 0.85 ) // Note: fixed from .86
{
if( d < 0.83 )
strcat(rval, "4/5"); // .8
else
strcat(rval, "5/6"); // .8333...
}
else // d >= .85
{
if( d < 0.87 ) // Note: fixed from .88
{
strcat(rval, "6/7"); // .8571
}
else // d >= .87
{
if( d < 0.88 ) // Note: fixed from .89
{
strcat(rval, "7/8"); // .875
}
else // d >= .88
{
if( d < 0.90 )
strcat(rval, "8/9"); // .8888...
else
strcat(rval, "9/10"); // .9
}
}
}
}
}
}
return rval;
}
여기에 대한 링크를 설명하는 수학을 뒤로 변환하수를 일부:
http://www.webmath.com/dec2fract.html
그리고 여기에는 예수에 대한 방법을 실제로 그것을 사용하여 VB(서 www.freevbcode.com/ShowCode.asp?ID=582):
Public Function Dec2Frac(ByVal f As Double) As String
Dim df As Double
Dim lUpperPart As Long
Dim lLowerPart As Long
lUpperPart = 1
lLowerPart = 1
df = lUpperPart / lLowerPart
While (df <> f)
If (df < f) Then
lUpperPart = lUpperPart + 1
Else
lLowerPart = lLowerPart + 1
lUpperPart = f * lLowerPart
End If
df = lUpperPart / lLowerPart
Wend
Dec2Frac = CStr(lUpperPart) & "/" & CStr(lLowerPart)
End Function
(에서 구글 검색:변환수수,진수로 변환하는 부분의 코드)
할 수 있습을 읽 모든 컴퓨터 과학자에 대해 알고 있어야 부동 소수점 연산.
야 할 것을 지정하는 일부 정밀도는 곱하여 큰 숫자:
3.141592 * 1000000 = 3141592
다음을 할 수 있습 fraction:
3 + (141592 / 1000000)
을 감소를 통해 GCD...
3 + (17699 / 125000)
그러나 방법은 없을 얻 도 분니다.습할 수 있습니다 상 분수를 전하는 코드 대신--기억 분수를 줄 수 있을 때 오버플로를 방지하기 위해!
여기에는 Perl 및 자바 스크립트의 버전 VB 코드에 의해 제안 devinmoore:
Perl:
sub dec2frac {
my $d = shift;
my $df = 1;
my $top = 1;
my $bot = 1;
while ($df != $d) {
if ($df < $d) {
$top += 1;
}
else {
$bot += 1;
$top = int($d * $bot);
}
$df = $top / $bot;
}
return "$top/$bot";
}
과 거의 동일한 자바 스크립트:
function dec2frac(d) {
var df = 1;
var top = 1;
var bot = 1;
while (df != d) {
if (df < d) {
top += 1;
}
else {
bot += 1;
top = parseInt(d * bot);
}
df = top / bot;
}
return top + '/' + bot;
}
C#구현
/// <summary>
/// Represents a rational number
/// </summary>
public struct Fraction
{
public int Numerator;
public int Denominator;
/// <summary>
/// Constructor
/// </summary>
public Fraction(int numerator, int denominator)
{
this.Numerator = numerator;
this.Denominator = denominator;
}
/// <summary>
/// Approximates a fraction from the provided double
/// </summary>
public static Fraction Parse(double d)
{
return ApproximateFraction(d);
}
/// <summary>
/// Returns this fraction expressed as a double, rounded to the specified number of decimal places.
/// Returns double.NaN if denominator is zero
/// </summary>
public double ToDouble(int decimalPlaces)
{
if (this.Denominator == 0)
return double.NaN;
return System.Math.Round(
Numerator / (double)Denominator,
decimalPlaces
);
}
/// <summary>
/// Approximates the provided value to a fraction.
/// http://stackoverflow.com/questions/95727/how-to-convert-floats-to-human-readable-fractions
/// </summary>
private static Fraction ApproximateFraction(double value)
{
const double EPSILON = .000001d;
int n = 1; // numerator
int d = 1; // denominator
double fraction = n / d;
while (System.Math.Abs(fraction - value) > EPSILON)
{
if (fraction < value)
{
n++;
}
else
{
d++;
n = (int)System.Math.Round(value * d);
}
fraction = n / (double)d;
}
return new Fraction(n, d);
}
}
이 선미-Brocot 리 유도 상당히 자연적인 방법으로 대략적인 실수로 분수와 함께 간단한 분모.
문제의 일부는 그래서 많은 분수에 실시간으로 쉽게는 것으로 해석이 분수.E.g.0.33 지 않 1/3,그것은 33/100.하지만 기억하는 경우 초등학교 교육,다음 변환하는 프로세스 진수 값으로 분수,그러나 그것의 가능성을 줄 당신은 당신이 원하는 무엇 때문에 대부분의 시간이 소수를 저장되지 않습에서 0.33 지만,0.329999999999998 니다.
자신에게 부탁하고 귀찮게 하지 않 이와 함께,그러나 당신이 필요한 경우 그 다음을 수행할 수 있습니다:
곱하면 원래 값으로 10 을 제거할 때까지 소수 부분입니다.을 유지하는 번호,그리고 그것을 사용으로 동기화를 요구합니다.다음 일련의 단순화하여 공통 분모.
그래서 0.4 것 4/10.당신이 다음에 대한 일반적인 약수 출발 저렴한 가치,아마 소수입니다.2 로 시작하는,당신이 볼 것이다면 2 분할 분자와 분모를 균일하게 확인하여 바닥 부분은과 같은 부문에 자체입니다.
floor(5/2) = 2
5/2 = 2.5
그래서 5 분할하지 않는 2 고르게 합니다.그래서 당신은 확인 다음 수 3.당신이 때까지 당신은 히트상의 제곱근 더 적습니다.
후에 당신은 그렇게 할 필요가 다음
이것은"알고리즘",단 Python 솔루션:http://docs.python.org/library/fractions.html
>>> from fractions import Fraction
>>> Fraction('3.1415926535897932').limit_denominator(1000)
Fraction(355, 113)
"이제 우리는 0.33,우리는 우리를 출력해야"1/3"."
무엇을 정밀도는 당신이 기대"솔루션"에 있는가?0.33 같지 않은 1/3.당신은 어떻게 인식하는"좋은"(읽기 쉬운)대답은?
무슨 상관 없이,가능한 알고리즘이 될 수 있습니다:
면 찾을 것으로 기대 가장 가까운 부분에서 양식을 X/Y Y 적은 다음 10 다음,반복할 수 있습니다 하지만 모든 9 가능한 Ys,각 Y 컴퓨팅 X,그리고 다음을 선택합니다.
내장 솔루션 R:
library(MASS)
fractions(0.666666666)
## [1] 2/3
이 사용하는 일부분을 계속 방법과 선택 cycles
고 max.denominator
논쟁 조정을 위한 정밀도입니다.
당신은 무엇을 알아낼 수준의 오류에 당신을 기꺼이 받아들입니다.하지 않는 모든 소수 줄일 것입니다 간단한 부분이다.나는 아마 선택 쉽게 나눌 수처럼,60,및 그 밖으로 얼마나 많은 60ths 은 값에 가장 가까운,다음 분율을 간소화 할 수 있습니다.
이 할 수 있는 프로그래밍 언어를 사용하여 다음과 같은 단계:
- 곱하고 나누기 10^x 는 10 개이 있는지 확인하는 데 필요 수가 없 소수 자릿수로 남아있다.예제:곱 0.33 10^2=100 그것을 만들 33 으로 나누를 받 33/100
- 을 줄 분자와의 분모 결과 분수에 의해 분해,당신까지 얻을 수 없는 정수에서 결과입니다.
- 결과 감수해야의 대답이다.
예제:0.2 =0.2x10^1/10^1 =2/10 =1/5
그래서 읽을 수 있는'으로 1 부 5'
하나의 솔루션은 저장소의 모든 숫자로 합리적인 숫자에 첫 번째 장소입니다.있는 라이브러리에 대한 합리적인 수산(예를 들어 GMP).을 사용하는 경우에는 OO 언어할 수 있습니다 단지 사용을 합리적인 수준 라이브러리를 교체하는 번호를 클래스입니다.
금융 프로그램을 다른 사람의 사이에서,사용하는 것은 이러한 솔루션을 할 수 있을 정확히 계산 및 보존하는 정밀도 수 있는 손실을 사용하여 일반습니다.
물론 그것이 많이 될 것입니다 느리게 할 수 있도록 실용적이지 않습니다.얼마나에 따라 계산을 할 필요가있는 방법 중요한 정밀도는 당신을위한 것입니다.
a = rational(1);
b = rational(3);
c = a / b;
print (c.asFraction) ---> "1/3"
print (c.asFloat) ----> "0.333333"
내가 생각하는 가장 좋은 방법은 첫째 변환 float 값을 ascii 표현입니다.C++에서 이용할 수 있 ostringstream 또는 C 에서 사용할 수 있습니다 sprintf.여기에 어떻게 C++:
ostringstream oss;
float num;
cin >> num;
oss << num;
string numStr = oss.str();
int i = numStr.length(), pow_ten = 0;
while (i > 0) {
if (numStr[i] == '.')
break;
pow_ten++;
i--;
}
for (int j = 1; j < pow_ten; j++) {
num *= 10.0;
}
cout << static_cast<int>(num) << "/" << pow(10, pow_ten - 1) << endl;
비슷한 접근 방식을 취할 수 있 직 C.
나중에 당신이 해야하는지 확인하려면 분수에서 가장 낮은 용어입니다.이 알고리즘은 정확한 대답을,즉0.33 것 출력"33/100",not"1/3." 그러나,0.4 을 줄 것"4/10,"이는 감소하는 경우 가장 낮은 용어는"2/5." 이되지 않을 수 있으로 강력한 엡프스테인의 솔루션이지만,저는 이것을 믿는 것은 더 간단합니다.
루비 호에 해결책:
0.33.rationalize.to_s # => "33/100"
0.4.rationalize.to_s # => "2/5"
에 레일이,ActiveRecord 숫자 특성을 변환할 수 있다:
product.size = 0.33
product.size.to_r.to_s # => "33/100"
응답에서는 C++,가 있다고 가정할 경우'BigInt'클래스 저장할 수 있는 무제한 크기의 정수입니다.
당신이 사용할 수 있는'unsigned long long'대신에,하지만 그것은 단지 작업을 위해 특정 값이 있습니다.
void GetRational(double val)
{
if (val == val+1) // Inf
throw "Infinite Value";
if (val != val) // NaN
throw "Undefined Value";
bool sign = false;
BigInt enumerator = 0;
BigInt denominator = 1;
if (val < 0)
{
val = -val;
sign = true;
}
while (val > 0)
{
unsigned int intVal = (unsigned int)val;
val -= intVal;
enumerator += intVal;
val *= 2;
enumerator *= 2;
denominator *= 2;
}
BigInt gcd = GCD(enumerator,denominator);
enumerator /= gcd;
denominator /= gcd;
Print(sign? "-":"+");
Print(enumerator);
Print("/");
Print(denominator);
// Or simply return {sign,enumerator,denominator} as you wish
}
BTW,GetRational(0.0)에서 반환하는"+0/1",그래서 당신은 수도 있고 싶은 이러한 사례를 지능적으로 처리하세요.
P.S.:이 코드에 자신의'RationalNum'클래스에 대한 몇 년 동안,그것은 시험되었습니다.
이 알고리즘에 의해 이안 Richards / 존 F. 케네디 하지만 반환합니다 좋은 분수를,그것도 아주 잘 실행의 측면에서 속도입니다.이것은 C#코드로에서 가져온 이 답변 입니다.
그것은 모든 것을 처리할 수 있습니다 double
값을 제외하고 특별한 값을 같이 할머니와+/-infinity,당신을 추가해야 할 경우 필요합니다.
반환합니다 new Fraction(numerator, denominator)
.대체하여 자신의 유형입니다.
더 많은 예제 값과 비교와 다른 알고리즘 여기로 이동
public Fraction RealToFraction(double value, double accuracy)
{
if (accuracy <= 0.0 || accuracy >= 1.0)
{
throw new ArgumentOutOfRangeException("accuracy", "Must be > 0 and < 1.");
}
int sign = Math.Sign(value);
if (sign == -1)
{
value = Math.Abs(value);
}
// Accuracy is the maximum relative error; convert to absolute maxError
double maxError = sign == 0 ? accuracy : value * accuracy;
int n = (int) Math.Floor(value);
value -= n;
if (value < maxError)
{
return new Fraction(sign * n, 1);
}
if (1 - maxError < value)
{
return new Fraction(sign * (n + 1), 1);
}
double z = value;
int previousDenominator = 0;
int denominator = 1;
int numerator;
do
{
z = 1.0 / (z - (int) z);
int temp = denominator;
denominator = denominator * (int) z + previousDenominator;
previousDenominator = temp;
numerator = Convert.ToInt32(value * denominator);
}
while (Math.Abs(value - (double) numerator / denominator) > maxError && z != (int) z);
return new Fraction((n * denominator + numerator) * sign, denominator);
}
예를 반환하는 값에는 이 알고리즘:
Accuracy: 1.0E-3 | Richards
Input | Result Error
======================| =============================
3 | 3/1 0
0.999999 | 1/1 1.0E-6
1.000001 | 1/1 -1.0E-6
0.50 (1/2) | 1/2 0
0.33... (1/3) | 1/3 0
0.67... (2/3) | 2/3 0
0.25 (1/4) | 1/4 0
0.11... (1/9) | 1/9 0
0.09... (1/11) | 1/11 0
0.62... (307/499) | 8/13 2.5E-4
0.14... (33/229) | 16/111 2.7E-4
0.05... (33/683) | 10/207 -1.5E-4
0.18... (100/541) | 17/92 -3.3E-4
0.06... (33/541) | 5/82 -3.7E-4
0.1 | 1/10 0
0.2 | 1/5 0
0.3 | 3/10 0
0.4 | 2/5 0
0.5 | 1/2 0
0.6 | 3/5 0
0.7 | 7/10 0
0.8 | 4/5 0
0.9 | 9/10 0
0.01 | 1/100 0
0.001 | 1/1000 0
0.0001 | 1/10000 0
0.33333333333 | 1/3 1.0E-11
0.333 | 333/1000 0
0.7777 | 7/9 1.0E-4
0.11 | 10/91 -1.0E-3
0.1111 | 1/9 1.0E-4
3.14 | 22/7 9.1E-4
3.14... (pi) | 22/7 4.0E-4
2.72... (e) | 87/32 1.7E-4
0.7454545454545 | 38/51 -4.8E-4
0.01024801004 | 2/195 8.2E-4
0.99011 | 100/101 -1.1E-5
0.26... (5/19) | 5/19 0
0.61... (37/61) | 17/28 9.7E-4
|
Accuracy: 1.0E-4 | Richards
Input | Result Error
======================| =============================
0.62... (307/499) | 299/486 -6.7E-6
0.05... (33/683) | 23/476 6.4E-5
0.06... (33/541) | 33/541 0
1E-05 | 1/99999 1.0E-5
0.7777 | 1109/1426 -1.8E-7
3.14... (pi) | 333/106 -2.6E-5
2.72... (e) | 193/71 1.0E-5
0.61... (37/61) | 37/61 0
당신은 두 개의 기본적인 문제는 이 하드:
1)부동 소수점되지 않는 정확한 표현하는 것을 의미가 있는 경우의 일부분"x/y"에 있는 결과 값의"z",당신의 일부는 알고리즘 결과를 반환할 수는 있다"x/y".
2)있는 무한 더 많은 불합리한 숫자보다 합리적이다.합리적인 수은 하나 표현할 수 있는 분수로.불합리한되는 사람은 할 수 없습니다.
그러나 저렴한 종류의 방법으로,이후 부동점 제한이 있는 정확성,다음할 수 있습니다 항상 그것을 표현으로 어떤 형태로의 세력이다.(나는 생각...)
위의 코드 변환 a s3
public static function toFrac(f:Number) : String
{
if (f>1)
{
var parte1:int;
var parte2:Number;
var resultado:String;
var loc:int = String(f).indexOf(".");
parte2 = Number(String(f).slice(loc, String(f).length));
parte1 = int(String(f).slice(0,loc));
resultado = toFrac(parte2);
parte1 *= int(resultado.slice(resultado.indexOf("/") + 1, resultado.length)) + int(resultado.slice(0, resultado.indexOf("/")));
resultado = String(parte1) + resultado.slice(resultado.indexOf("/"), resultado.length)
return resultado;
}
if( f < 0.47 )
if( f < 0.25 )
if( f < 0.16 )
if( f < 0.13 )
if( f < 0.11 )
return "1/10";
else
return "1/9";
else
if( f < 0.14 )
return "1/8";
else
return "1/7";
else
if( f < 0.19 )
return "1/6";
else
if( f < 0.22 )
return "1/5";
else
return "2/9";
else
if( f < 0.38 )
if( f < 0.29 )
return "1/4";
else
if( f < 0.31 )
return "2/7";
else
return "1/3";
else
if( f < 0.43 )
if( f < 0.40 )
return "3/8";
else
return "2/5";
else
if( f < 0.44 )
return "3/7";
else
return "4/9";
else
if( f < 0.71 )
if( f < 0.60 )
if( f < 0.56 )
return "1/2";
else
if( f < 0.57 )
return "5/9";
else
return "4/7";
else
if( f < 0.63 )
return "3/5";
else
if( f < 0.66 )
return "5/8";
else
return "2/3";
else
if( f < 0.80 )
if( f < 0.74 )
return "5/7";
else
if(f < 0.78 )
return "3/4";
else
return "7/9";
else
if( f < 0.86 )
if( f < 0.83 )
return "4/5";
else
return "5/6";
else
if( f < 0.88 )
return "6/7";
else
if( f < 0.89 )
return "7/8";
else
if( f < 0.90 )
return "8/9";
else
return "9/10";
}
이제 우리는 0.33,우리는 우리를 출력해야"1/3".가 있는 경우에 우리는"0.4",리 를 출력해야"2/5".
그것은 잘못된 일반적인 경우에는,때문에 1/3=0.3333333=0.(3) 또한,그것은 불가능을 찾아서 위의 제안 솔루션은 진수로 변환할 수 있 일부분으로 정의 정밀기 때문에,출력이 항상 부분이다.
하지만,나는 나의 포괄적 인 기능으로 많은 옵션에 기반의 아이디어 무한한 기하학적 시리즈, 특히에서 공식:
처음에 이 기능을 찾으려고 하는 기간의 일부로서 문자열 표현입니다.후에는 위에 설명한 공식을 적용합니다.
합리적인 숫자가 코드에서 빌린 Stephen M.McKamey 합리적인 숫자를 구현 C#.희망이 없고 매우 어렵 포트 내 코드는 다른 언어가 있습니다.
/// <summary>
/// Convert decimal to fraction
/// </summary>
/// <param name="value">decimal value to convert</param>
/// <param name="result">result fraction if conversation is succsess</param>
/// <param name="decimalPlaces">precision of considereation frac part of value</param>
/// <param name="trimZeroes">trim zeroes on the right part of the value or not</param>
/// <param name="minPeriodRepeat">minimum period repeating</param>
/// <param name="digitsForReal">precision for determination value to real if period has not been founded</param>
/// <returns></returns>
public static bool FromDecimal(decimal value, out Rational<T> result,
int decimalPlaces = 28, bool trimZeroes = false, decimal minPeriodRepeat = 2, int digitsForReal = 9)
{
var valueStr = value.ToString("0.0000000000000000000000000000", CultureInfo.InvariantCulture);
var strs = valueStr.Split('.');
long intPart = long.Parse(strs[0]);
string fracPartTrimEnd = strs[1].TrimEnd(new char[] { '0' });
string fracPart;
if (trimZeroes)
{
fracPart = fracPartTrimEnd;
decimalPlaces = Math.Min(decimalPlaces, fracPart.Length);
}
else
fracPart = strs[1];
result = new Rational<T>();
try
{
string periodPart;
bool periodFound = false;
int i;
for (i = 0; i < fracPart.Length; i++)
{
if (fracPart[i] == '0' && i != 0)
continue;
for (int j = i + 1; j < fracPart.Length; j++)
{
periodPart = fracPart.Substring(i, j - i);
periodFound = true;
decimal periodRepeat = 1;
decimal periodStep = 1.0m / periodPart.Length;
var upperBound = Math.Min(fracPart.Length, decimalPlaces);
int k;
for (k = i + periodPart.Length; k < upperBound; k += 1)
{
if (periodPart[(k - i) % periodPart.Length] != fracPart[k])
{
periodFound = false;
break;
}
periodRepeat += periodStep;
}
if (!periodFound && upperBound - k <= periodPart.Length && periodPart[(upperBound - i) % periodPart.Length] > '5')
{
var ind = (k - i) % periodPart.Length;
var regroupedPeriod = (periodPart.Substring(ind) + periodPart.Remove(ind)).Substring(0, upperBound - k);
ulong periodTailPlusOne = ulong.Parse(regroupedPeriod) + 1;
ulong fracTail = ulong.Parse(fracPart.Substring(k, regroupedPeriod.Length));
if (periodTailPlusOne == fracTail)
periodFound = true;
}
if (periodFound && periodRepeat >= minPeriodRepeat)
{
result = FromDecimal(strs[0], fracPart.Substring(0, i), periodPart);
break;
}
else
periodFound = false;
}
if (periodFound)
break;
}
if (!periodFound)
{
if (fracPartTrimEnd.Length >= digitsForReal)
return false;
else
{
result = new Rational<T>(long.Parse(strs[0]), 1, false);
if (fracPartTrimEnd.Length != 0)
result = new Rational<T>(ulong.Parse(fracPartTrimEnd), TenInPower(fracPartTrimEnd.Length));
return true;
}
}
return true;
}
catch
{
return false;
}
}
public static Rational<T> FromDecimal(string intPart, string fracPart, string periodPart)
{
Rational<T> firstFracPart;
if (fracPart != null && fracPart.Length != 0)
{
ulong denominator = TenInPower(fracPart.Length);
firstFracPart = new Rational<T>(ulong.Parse(fracPart), denominator);
}
else
firstFracPart = new Rational<T>(0, 1, false);
Rational<T> secondFracPart;
if (periodPart != null && periodPart.Length != 0)
secondFracPart =
new Rational<T>(ulong.Parse(periodPart), TenInPower(fracPart.Length)) *
new Rational<T>(1, Nines((ulong)periodPart.Length), false);
else
secondFracPart = new Rational<T>(0, 1, false);
var result = firstFracPart + secondFracPart;
if (intPart != null && intPart.Length != 0)
{
long intPartLong = long.Parse(intPart);
result = new Rational<T>(intPartLong, 1, false) + (intPartLong == 0 ? 1 : Math.Sign(intPartLong)) * result;
}
return result;
}
private static ulong TenInPower(int power)
{
ulong result = 1;
for (int l = 0; l < power; l++)
result *= 10;
return result;
}
private static decimal TenInNegPower(int power)
{
decimal result = 1;
for (int l = 0; l > power; l--)
result /= 10.0m;
return result;
}
private static ulong Nines(ulong power)
{
ulong result = 9;
if (power >= 0)
for (ulong l = 0; l < power - 1; l++)
result = result * 10 + 9;
return result;
}
거기에 몇 가지 예의 using:
Rational<long>.FromDecimal(0.33333333m, out r, 8, false);
// then r == 1 / 3;
Rational<long>.FromDecimal(0.33333333m, out r, 9, false);
// then r == 33333333 / 100000000;
귀하의 경우로 오른쪽 부분을 제로 부분 조정:
Rational<long>.FromDecimal(0.33m, out r, 28, true);
// then r == 1 / 3;
Rational<long>.FromDecimal(0.33m, out r, 28, true);
// then r == 33 / 100;
분 기간 demostration:
Rational<long>.FromDecimal(0.123412m, out r, 28, true, 1.5m));
// then r == 1234 / 9999;
Rational<long>.FromDecimal(0.123412m, out r, 28, true, 1.6m));
// then r == 123412 / 1000000; because of minimu repeating of period is 0.1234123 in this case.
반올림 끝:
Rational<long>.FromDecimal(0.8888888888888888888888888889m, out r));
// then r == 8 == 9;
가장 흥미로운 경우:
Rational<long>.FromDecimal(0.12345678m, out r, 28, true, 2, 9);
// then r == 12345678 / 100000000;
Rational<long>.FromDecimal(0.12345678m, out r, 28, true, 2, 8);
// Conversation failed, because of period has not been founded and there are too many digits in fraction part of input value.
Rational<long>.FromDecimal(0.12121212121212121m, out r, 28, true, 2, 9));
// then r == 4 / 33; Despite of too many digits in input value, period has been founded. Thus it's possible to convert value to fraction.
다른 테스트와 코드 모두에서 찾을 수 있습니다 내 MathFunctions github 에서 라이브러리.
여기에 빠르고 더러운 구현에서 javascript 를 사용하는 폭력적인 접근 방식이다.만에 최적화되어,그것은 작품에서 미리 정의된 범위의 분수: http://jsfiddle.net/PdL23/1/
/* This should convert any decimals to a simplified fraction within the range specified by the two for loops. Haven't done any thorough testing, but it seems to work fine.
I have set the bounds for numerator and denominator to 20, 20... but you can increase this if you want in the two for loops.
Disclaimer: Its not at all optimized. (Feel free to create an improved version.)
*/
decimalToSimplifiedFraction = function(n) {
for(num = 1; num < 20; num++) { // "num" is the potential numerator
for(den = 1; den < 20; den++) { // "den" is the potential denominator
var multiplyByInverse = (n * den ) / num;
var roundingError = Math.round(multiplyByInverse) - multiplyByInverse;
// Checking if we have found the inverse of the number,
if((Math.round(multiplyByInverse) == 1) && (Math.abs(roundingError) < 0.01)) {
return num + "/" + den;
}
}
}
};
//Put in your test number here.
var floatNumber = 2.56;
alert(floatNumber + " = " + decimalToSimplifiedFraction(floatNumber));
이것은 영감으로 접근 방식에 의해 사용 JPS.
으로 많은 사람들이 명시된 당신이 정말로 변환할 수 없습니다 부동 소수점이 다시 일(지 않는 한 그것의 매우 정확한 같은 .25).물론을 만들 수 있습니 어떤 종류의 모습에 대한의 큰 배열을 분수와 사용하여 어떤 종류의 fuzzy 논리를 생산하는 결과를 찾고 있습니다.다시 없을 정확하지만 당신은 정의할 필요가 낮은 범위의 얼마나 큰 원하는 분모 갈 수 있습니다.
.32 < x < .34=1/3 또는 무언가 다음과 같다.
여기에 구현하기 위한 http://github.com/valodzka/frac
Math.frac(0.2, 100) # => (1/5)
Math.frac(0.33, 10) # => (1/3)
Math.frac(0.33, 100) # => (33/100)
에 걸쳐 온 나는 특히 우아하는 메인 솔루션을 사용하의 anamorphism.이에 따라 달라집 재귀-계획 패키지입니다.
{-# LANGUAGE AllowAmbiguousTypes #-}
{-# LANGUAGE FlexibleContexts #-}
import Control.Applicative (liftA2)
import Control.Monad (ap)
import Data.Functor.Foldable
import Data.Ratio (Ratio, (%))
isInteger :: (RealFrac a) => a -> Bool
isInteger = ((==) <*>) (realToFrac . floor)
continuedFraction :: (RealFrac a) => a -> [Int]
continuedFraction = liftA2 (:) floor (ana coalgebra)
where coalgebra x
| isInteger x = Nil
| otherwise = Cons (floor alpha) alpha
where alpha = 1 / (x - realToFrac (floor x))
collapseFraction :: (Integral a) => [Int] -> Ratio a
collapseFraction [x] = fromIntegral x % 1
collapseFraction (x:xs) = (fromIntegral x % 1) + 1 / collapseFraction xs
-- | Use the nth convergent to approximate x
approximate :: (RealFrac a, Integral b) => a -> Int -> Ratio b
approximate x n = collapseFraction $ take n (continuedFraction x)
당신이 시도하는 경우 이에 ghci,그것은 정말 작업을 수행!
λ:> approximate pi 2
22 % 7