인수 표준화


32

배경

여기에있는 대부분의 사람들은 소수, 소수, 이진수, 16 진수, 8 진수와 같은 몇 가지 정수 기본 시스템에 익숙해야합니다. 예를 들어 16 진수 시스템에서 숫자 abc.de 16 은 다음을 나타냅니다.

a*16^2 + b*16^1 + c*16^0 + d*16^-1 + e*16^-2

그러나 비이성적 인 숫자와 같이 정수가 아닌 기본을 사용할 수도 있습니다. 그러한 기초가 황금비 φ = (1 + √5) / 2 ≈ 1.618 ...을 사용하면 . 이들은 정수 염기와 유사하게 정의됩니다. 따라서 숫자 abc.de φ (여기서 a 에서 e 는 정수)입니다.

a*φ^2 + b*φ^1 + c*φ^0 + d*φ^-1 + e*φ^-2

원칙적으로 모든 숫자는 음수가 될 수 있습니다 (우리는 그것에 익숙하지는 않지만)-선행으로 음수를 나타냅니다 ~. 이 질문의 목적을 위해 우리는에서 ~9~ 까지의 숫자로 제한 9하므로 숫자를 하나의 문자열로 분명하게 쓸 수 있습니다 (사이에 물결표가 있음). 그래서

-2*φ^2 + 9*φ^1 + 0*φ^0 + -4*φ^-1 + 3*φ^-2

로 작성됩니다 ~290.~43. 우리는 그러한 숫자를 인수 라고 부릅니다 .

phinary 수는 항상 표현 될 수 표준 양식 표현은 숫자를 사용하는 수단 10포함하지 않고, 11어디서나, 그리고 선택적 빼기 기호 전체 번호가 부정적임을 나타냅니다. 흥미롭게도 모든 정수는 표준 형식으로 고유 한 유한 표현을 갖습니다.

표준 형식이 아닌 표현은 다음 관찰을 사용하여 항상 표준 형식으로 변환 할 수 있습니다.

  1. 011 φ = 100 φ2 = φ + 1 이므로 )
  2. 0200 φ = 1001 φ2 + 1 / φ = 2φ이므로)
  3. 0 ~ 10 φ = ~ 101 φ (φ-1 / φ = 1이므로)

게다가:

  1. 가장 중요한 자리 인 경우 ~1(숫자의 나머지 부분은 표준 양식 인 상태), 수는 음, 우리는 모두 교환하여 표준 형태로 변환 할 수 있습니다 1~1, 마이너스 부호를 붙이는, 우리까지 다시 위의 세 가지 규칙을 적용 표준 양식을 얻습니다.

다음은 이러한 정규화의 예입니다 (각 숫자 위치를 정렬하기 위해 양수에 추가 공백을 사용하고 있습니다). 1~3.2~1φ

      1~3. 2~1φ         Rule:
=     0~2. 3~1φ         (3)
=    ~1~1. 4~1φ         (3)
=  ~1 0 0. 4~1φ         (3)
=  ~1 0 0. 3 0 1φ       (3)
=  ~1 0 1. 1 0 2φ       (2)
=  ~1 1 0. 0 0 2φ       (1)
=  ~1 1 0. 0 1 0 0 1φ   (2)
= - 1~1 0. 0~1 0 0~1φ   (4)
= - 0 0 1. 0~1 0 0~1φ   (3)
= - 0 0 1.~1 0 1 0~1φ   (3)
= - 0 0 0. 0 1 1 0~1φ   (3)
= - 0 0 0. 0 1 1~1 0 1φ (3)
= - 0 0 0. 0 1 0 0 1 1φ (3)
= - 0 0 0. 0 1 0 1 0 0φ (1)

항복 .-0.0101φ

더 자세히 읽으 려면 Wikipedia 에 주제에 대한 유익한 기사 가 있습니다.

도전

따라서 또는 다른 방법으로, (위에서 설명한 것처럼) 9 진수를 나타내는 문자열이 주어지면 선행 또는 후행 0없이 표준 형식을 출력하는 프로그램 또는 함수를 작성하십시오. 입력에 반드시 피닌 포인트가 포함되어 있지는 않지만 항상 왼쪽에있는 숫자가 포함됩니다 (그래서 no .123). 출력은 항상 피닌 포인트와 그 왼쪽에 적어도 하나의 숫자를 포함해야합니다.

STDIN, ARGV 또는 함수 인수를 통해 입력을 받아 결과를 리턴하거나 STDOUT에 인쇄 할 수 있습니다.

임의의 (유효한) 입력에 대해 원칙적으로 정확하고 정확한 한, 즉 구현을 중단시킬 수있는 유일한 한계는 내장 된 크기와 같은 기술적 한계 여야합니다 데이터 유형 또는 사용 가능한 RAM. 예를 들어, 부동 소수점 숫자로 입력을 평가 한 다음 탐욕적으로 숫자를 선택하는 것은 허용되지 않습니다. 부동 소수점 부정확성이 잘못된 결과를 초래하는 입력을 찾을 수 있기 때문입니다.

이것은 코드 골프이며, 가장 짧은 대답 (바이트)이 이깁니다.

테스트 사례

Input       Output

1           1.
9           10010.0101
1.618       10000.0000101
1~3.2~1     -0.0101
0.~1021     0. (or -0.)
105.~2      1010.0101
~31~5.~1    -100000.1001

이제 숫자에 음수를 사용하고 싶습니다! 1 ~ 3 * 6 == 5 ~ 8
Aaron

답변:


6

자바 스크립트 (ES6) - 446 418 422 420 바이트

축소 :

F=s=>{D=[];z='000000000';N=t=n=i=e=0;s=(z+s.replace(/^([^.]*)$/,'$1.')+z).replace(/~/g,'-').replace(/-?\d/g,s=>((D[n++]=s/1),0));for(;i<n-3;i=j){if(p=D[j=i+1]){if(!e&&p<0){D=D.map(k=>-k);N=~N;p=-p}e=1}d=D[i];x=D[i+2];m=D[i+3];if(p<0){d--;p++;x++;e=j=0}if(p>1){d++;m++;p-=2;e=j=0}if(!d&&p*x==1){d=p;e=j=p=x=0}D[i]=d;D[i+1]=p;D[i+2]=x;D[i+3]=m}return(N?'-':'')+s.replace(/0/g,()=>D[t++]).replace(/^(0(?!\.))+|0+$/g,'')}

넓히는:

F = s => {
    D = [];
    z = '000000000';
    N = t = n = i = e = 0;
    s = (z + s.replace( /^([^.]*)$/, '$1.' ) + z).replace( /~/g, '-' ).
        replace( /-?\d/g, s => ((D[n++]=s/1),0) );

    for( ; i < n-3; i = j ) {
        if( p = D[j = i+1] ) {
            if( !e && p < 0 ) {
                D = D.map( k=>-k );
                N = ~N;
                p = -p;
            }
            e = 1;
        }
        d = D[i];
        x = D[i+2];
        m = D[i+3];

        if( p < 0 ) {
            d--;
            p++;
            x++;
            e = j = 0;
        }
        if( p > 1 ) {
            d++;
            m++;
            p-=2;
            e = j = 0;
        }
        if( !d && p*x == 1 ) {
            d = p;
            e = j = p = x = 0;
        }

        D[i] = d;
        D[i+1] = p;
        D[i+2] = x;
        D[i+3] = m;
    }

    return (N ? '-' : '') + s.replace( /0/g, ()=>D[t++] ).replace( /^(0(?!\.))+|0+$/g, '' );
}

코드는 F지정된 변환을 수행 하는 함수 를 생성합니다 .

골프하기 어려운 문제입니다. 코드의 단순화를 방해하는 수많은 엣지 케이스가 발생합니다. 특히, 부정을 다루는 것은 구문 분석과 논리적 처리 측면에서 고통입니다.

코드는 "합리적인 범위의"입력 만 처리한다는 점에 유의해야합니다. 바운드없이 함수의 도메인을 확장하기 위해 0의 z수를 늘리고 while( c++ < 99 )루프를 경계로하는 상수를 늘릴 수 있습니다. 현재 지원되는 범위는 제공된 테스트 사례에 대해 이미 과잉입니다.

샘플 출력

F('1')          1.
F('9')          10010.0101
F('1~3.2~1')    -0.0101
F('0.~1021')    -0.
F('105.~2')     1010.0101
F('~31~5.~1')   -100000.1001

-0.꽤 아니지만, 대답은 여전히 올바른 것입니다. 필요한 경우 고칠 수 있습니다.


@ MartinBüttner : 가능하지만 어려울 것입니다. 전체 입력에 대한 "패스"수를 제한하며 각 패스는 여러 작업으로 구성됩니다. 내 직감 느낌은 패스의 수는 어느 정상화하는 데 필요한 것입니다 n-digit 입력 사이 어딘가에있을 것입니다 nn log(n). 어쨌든, 패스 수는 추가 된 모든 문자에 대해 10 배 증가 할 수 있습니다. z상수 에서 0의 숫자 도 흥미로운 문제입니다. 가능한 모든 입력에 대해 9가 과도하다고 생각합니다 .
COTO

@ MartinBüttner : 감사합니다. 캐릭터 클래스에서 이스케이프를 제거했습니다. 에 대해서는 $0Javascript가 지원하지 않습니다. 또는 적어도 Firefox는 그렇지 않습니다. : P
COTO

좋아, 버퍼로 7 개 이상의 선행 0이 필요하지 않다고 생각하지만 후행 0은 추정하기가 조금 더 어렵다고 생각합니다. 외부 루프에 관해서는, 그냥 while 루프를 만들거나 내부 for 루프에 통합하고 더 이상 변경 사항이 발견되지 않으면 나아질 필요조차 없다고 생각합니다. 내 관점은 그 점에서 약간 더 명확했을 수 있지만 "원칙적으로 임의의 (유효한) 입력에 대해 정확하고 정확한"라는 이론적 한계는 내장 데이터 유형 / RAM의 크기 여야한다는 것을 의미했습니다.
Martin Ender

1
@COTO에 1 바이트를 저장, 당신의 첫 번째 부분을 이동 시도 할 수 있습니다 for( i = e = 0; i < n-3; i = j )에 의해 for(; i < n-3; i = j )상단에 선언을 이동하고 N = t = n = 0;교체N = t = n = i = e = 0;
이스마엘 미구엘

1
@IsmaelMiguel : j의 값은 일정하지 않습니다 i+1. 세 if블록에서 j으로 재설정됩니다 0. 따라서 첫 번째 if블록 이후의 어느 시점에서든 의 프록시로 사용할 수 없습니다 i+1. 변수 i자체는 루프가 끝날 때까지 for값이 바로 사용되므로 루프가 끝날 때까지 (의 세 번째 문을 사용하여) 변수를 업데이트 할 수 없습니다 . 그러나 그렇게 말하면 어쩌면 뭔가 빠진 것 같습니다. 코드를 단축하고 테스트 한 후에도 작동하는지 확인하려면 pastebin.com에 사본을 게시하고 여기에 링크하십시오. 답변에서 귀하에게 크레딧을 연장 할 것입니다. :)
COTO

2

하스켈, 336 바이트

z=[0,0]
g[a,b]|a*b<0=g[b,a+b]
g x=x<z
k![a,b,c,d]=[b,a+b,d-c+read k,c]
p('.':s)=1:0:2`drop`p s
p('~':k:s)=['-',k]!p s
p(k:s)=[k]!p s
p[]=1:0:z
[1,0]&y='.':z?y
[a,b]&y=[b,a+b]?y
x@[a,b]?y@[c,d]|x==z,y==z=""|g y='-':x?[-c,-d]|g[c-1,d]='0':x&[d,c+d]|g[c,d-1]='1':x&[d,c+d-1]|0<1=[b-a,a]?[d-c,c]
m[a,b,c,d]=[1,0]?[a*d+b*c-a*c,a*c+b*d]
f=m.p

이것은 욕심 많은 알고리즘이지만 부동 소수점 오류를 피하기 위해 [a,b]숫자 a + ( a , b ∈ ℤ)를 정확하게 표현 합니다. a + <0 g[a,b]인지 테스트합니다 . 사용 예 :

*Main> f "9"
"10010.0101"
*Main> f "1~3.2~1"
"-0.0101"
*Main> f "0.~1021"
"0."
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.