둥근 분수 음수가 아니고 분모가 양수인 경우

분수를 10 진수로 변환하고 해당 숫자를 저장하려면 특정 양의 메모리 만 사용하기 때문에 반올림해야하는 경우가 있습니다. 소수점 5 자리 만 저장할 수 있고 5/3는 1.6667이된다고 가정합니다. 소수점 이하 두 자리 만 저장할 수 있으면 1.7이됩니다 (현재는 항상 0과 9.99 사이에 있다고 가정).

1.7로 반올림을 시도하고 분수를 되 찾으려면 1.7이 반올림 된 숫자라는 것을 알기 때문에 어려울 수 있습니다. 물론 당신은 17/10을 시도 할 수 있지만 그것은 ‘우아한’5/3에 비해 ‘추악한’분수입니다.

따라서 목표는 이제 가장 작은 분모가 b 인 분수 a / b를 찾는 것입니다. 이로 인해 올바로 반올림되면 소수점이 반올림됩니다.

세부

입력에 0과 1 사이의 숫자 ( ‘포함’)와 10 (제외) 사이의 숫자가 포함 된 문자열이 포함됩니다. 첫 번째 숫자 다음에. 하자 말은 n숫자의 수를 나타낸다. [numerator, denominator]분자는 음수가 아니고 분모가 양수인 경우 두 개의 정수의 목록 / 배열 또는 합리적인 데이터 유형 (자체를 만들거나 내장을 사용할 수 있음)이어야합니다 . 분수 분자 / 분모는 n숫자 ( n-1소수점 뒤의 숫자)로 올바르게 반올림 될 때 입력과 같아야합니다 .

제한 사항 : 하나의 루프 문 만 허용됩니다. 즉 , 전체 코드에서 하나의 단일 반복문 (예 for: while또는 goto등)뿐만 아니라 목록 / 배열의 모든 요소에 코드를 적용 map하거나 fold적용하는 기능적 루프 만 사용할 수 있지만 자유롭게 ‘남용’할 수 있습니다 또는 재귀 등을 사용하십시오.

함수를 작성해야합니다. 언어에 함수가 없거나 (있는 경우에도) 입력이 변수 (또는 stdin을 통해 입력)에 저장되어 있다고 가정하고 결과를 인쇄하거나 파일에 쓸 수 있습니다. 가장 적은 바이트 수가 이깁니다.

반올림

반올림은 ‘기존의’반올림 규칙을 따라야합니다. 즉, 마지막으로 잘릴 숫자가 5 이상이면 반올림하고 다른 경우에는 반올림합니다. 예를 들면 다음과 같습니다.

반올림하면 4.5494가 발생합니다.

  • 1 자리 : 5
  • 2 자리 : 4.5
  • 3 자리 : 4.55
  • 4 자리 : 4.549

다음 테스트 사례 및 기타 ‘관심있는’사례를 포함하십시오.

Input 1.7     Output 5/3
Input 0.      Output 0/1
Input 0.001   Output 1/667
Input 3.1416  Output 355/113


답변

CJam, 41 40 36 바이트

Q'./1=,:L0\{;)_Qd*mo_d2$/LmOQd-}g'/@

입력 문자열이 Q에 저장되어 질문에서 명시 적으로 허용한다고 가정합니다. 온라인으로 사용해보십시오.

테스트 사례

$ for d in 1.7 0. 0.001 3.1416; do cjam <(echo "\"$d\":Q;
> Q'./1=,:L0\{;)_Qd*mo_d2$/LmOQd-}g'/@
> "); echo; done
5/3
0/1
1/667
355/113

작동 원리

Q'./1=,:L  " Count the number of characters after the dot and store it in L.     ";
0\         " Push 0 (denominator) and swap it with L (dummy value).              ";
{          "                                                                     ";
  ;        " Discard the topmost item from the stack (numerator or dummy value). ";
  )        " Increment the denominator.                                          ";
  _Qd*mo   " Multiply a copy by Double(Q) and round.                             ";
  _d2$/    " Cast a copy to Double and it divide it by the denominator.          ";
  LmO      " Round to L digits.                                                  ";
  Qd       " If the result is not Double(Q),                                     ";
}g         " repeat the loop.                                                    ";
./@        " Push a slash and rotate the denominator on top of it.               ";

답변

T-SQL 254

T-SQL은 이런 종류의 제품에는 실제로 적합하지 않지만 시도하는 것은 재미 있습니다. 분모가 높을수록 성능이 실제로 나빠집니다. 1000의 분모로 제한됩니다.

입력은 부동 변수 @

WITH e AS(SELECT *FROM(VALUES(1),(2),(3),(4),(5),(6),(7),(8),(9),(0))n(n)),t AS(SELECT ROW_NUMBER()OVER(ORDER BY(SELECT \))N FROM e a,e b,e c,e d)SELECT TOP 1concat(n.n,'/',d.n)FROM t d,t n WHERE round(n.n/(d.n+.0),len(parsename(@,1)))=@ ORDER BY d.n,n.n

쿼리 분석

WITH                                      -- Start CTE(Common Table Expression)
 e AS(                                    --Create a set of 10 rows
   SELECT *
   FROM(VALUES(1),(2),(3),(4),(5),(6),(7),(8),(9),(0))n(n)
 ),
 t AS(
   SELECT ROW_NUMBER()OVER(ORDER BY(SELECT \))N
   FROM e a,e b,e c,e d                   --Cross join e to produce 1000 numbered rows
 )
SELECT
  TOP 1                                   --Grab first result
  concat(n.n,'/',d.n)                     --Build output
FROM t d,t n                              --Cross join t against itself for denominator and numerator
WHERE round(
  n.n/(d.n+.0),                           --Force float division with +.0
  len(parsename(@,1))                     --Get rounding length
  )=@                                     --Filter where the rounded result = input
ORDER BY d.n,n.n                          --Order by denominator then numerator

답변

하스켈, 62 59

이름 만 길지 않았다면 …

import Data.Ratio
f s=approxRational(read s)$50/10^length s

이것은 Rational값을 반환하는 함수 입니다.

설명 :
이 함수 approxRational는 float 숫자와 float epsilon을 취하고 입력의 거리 epsilon에있는 가장 간단한 이성을 반환하는 함수입니다. 기본적으로 플로트의 가장 간단한 근사값을 “용서할 수있는 오류”거리에서 합리적으로 반환합니다.

우리가 사용하기 위해이 기능을 이용합시다. 이를 위해 우리는 주어진 수로 반올림되는 수레의 면적이 무엇인지 알아 내야합니다. 이것을 approxRational함수에 넣는 것은 우리에게 답을 줄 것입니다.

예를 들어 1.7을 봅시다. 1.7로 반올림되는 가장 낮은 플로트는 1.65입니다. 더 낮은 값은 1.7로 반올림되지 않습니다. 마찬가지로 1.7로 반올림 된 수레의 상한은 1.75입니다.
두 한계는 경계가 입력 번호 +/- 0.05입니다. 이 거리가 항상 있음을 쉽게 알 수 있습니다 5 * 10 ^ -(the length of the input - 1)(-1은 입력에 항상 ‘.’가 있기 때문입니다). 여기에서 코드는 매우 간단합니다.

테스트 사례 :

*Main> map f ["1.7", "0.001", "3.1416"]
[5 % 3,1 % 667,355 % 113]

불행히도 “0”에서는 작동하지 않습니다. Haskell의 파서 함수는 .float의 끝에서를 인식하지 못하기 때문에 로 교체 read s하여 5 바이트 동안 고정 할 수 있습니다 read$s++"0".


답변

루비, 127125 바이트

f=->n{b=q=r=(m=n.sub(?.,'').to_r)/d=10**p=n.count('0-9')-1
b=r if(r=(q*d-=1).round.to_r/d).round(p).to_f.to_s==n while d>1
b}

f결과를로 반환 하는 함수 를 정의합니다 Rational. 예를 들어이 코드를 추가하면

p f["1.7"]
p f["0."]
p f["0.001"]
p f["3.1416"]

당신은 얻을

(5/3)
(0/1)
(1/667)
(355/113)

루프는 분모 위에 있습니다. 예 31416/10000를 들어 마지막 예제 와 같이 전체 분수로 시작합니다 . 그런 다음 분모를 낮추고 분자를 비례 적으로 줄입니다 (반올림). 결과 합리적이 입력 숫자와 동일하게 반올림되면 새로운 최고 분수를 기억합니다.


답변

매스 매 티카, 49 53 자

Rationalize[ToExpression@#,5 10^(1-StringLength@#)]&@

용법:

Rationalize[ToExpression@#,5 10^(1-StringLength@#)]&@"1.7"

산출:

5/3

테스트 사례 :

input: 1.7     output: 5/3
input: 0.      output: 0
input: 0.001   output: 1/999
input: 3.1416  output: 355/113

0.001 사건은 나를 이상하게 생각한다. 1/667 사례를 찾지 못하면 설명에 따라 합리화 기능이 작동하지 않았기 때문입니다. 지정된 범위 내에있는 가장 작은 분모를 가진 숫자를 출력해야합니다.


답변

Python 2.7+, 111 자

모든 언어로 끔찍한 코드를 작성할 수 있다는 증거 :

def f(s):
 t,e,y=float(s),50*10**-len(s),1;n=d=x=0
 while x|y:n,d=n+x,d+y;a=1.*n/d;x,y=a<t-e,a>t+e
 return n,d

산출

>>> [f(s) for s in ("1.7", "0.", "0.001", "3.1416")]
[(5, 3), (0, 1), (1, 667), (355, 113)]

답변

APL, 50

2↑⍎⍕(⍎x←⍞){50>|(10*⍴x)×⍺-⍵÷⍨n←⌊.5+⍺×⍵:n ⍵⋄''}¨⍳1e5

긴로서 당신은 계산하지 않는 evaltoString루프로

설명

접근 방법은 분모로 1 ~ 10000 이상을 반복하고 부동 소수점과 가장 일치하는 분자를 계산 한 다음 오류가 범위 내에 있는지 확인하는 것입니다. 마지막으로, 발견 된 모든 분수에서 가장 작은 쌍을 선택하십시오.

(⍎x←⍞)화면에서 문자열 입력을 받고에 할당 x하고 eval
⍳1e51에서 10000 사이의 배열 생성 배열의
{...}¨각 요소에 대해 함수와 (⍎x←⍞)인수를 사용하여 함수를 호출하십시오 (루프)

⍺×⍵곱하기 인수
⌊.5+라운드 오프 (다음 아래로 반올림 0.5을 추가하여)
n←할당에 n
⍺-⍵÷⍨오른쪽 인자에 의해 분할 후 왼쪽 인자에서 빼기
(10*⍴x)ד의 길이의 힘에 10을 곱 x
|절대 값 가져
50>미만 50 (길이가 있는지 확인을 x더 2입니다 dp 수보다 0.5이므로 대신 50을 사용하십시오.)
:n ⍵⋄''이전 검사에서 true를 반환하면 배열 n과 오른쪽 인수를 반환하고 그렇지 않으면 빈 문자열을 반환합니다.

⍎⍕ toString그런 다음 eval배열의 모든 숫자의 배열을 가져옵니다.
2↑발견 된 첫 번째 분자 분모 쌍 인 처음 두 요소 만 선택하십시오.