ファイナリ番号を標準化する


32

バックグラウンド

ほとんどの人は、10進数、2進数、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のφは、(ここに、eは桁の整数である)を表すことになります

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

原則として、数字のいずれかが負になる可能性があることに注意してください(私たちはそれに慣れていませんが)-先行する負の数字を表します~。この質問の目的のために我々はから数字に自分自身を制限~9する9ので、我々は明確に(間にチルダ付き)1つの文字列として番号を書くことができます。そう

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

と書かれ~290.~43ます。私たちは、このような番号に電話phinary数

進数は常に標準形式で表すことができます。これは、数字1とのみを使用し011どこにも含まず、オプションのマイナス記号を付けて数字全体が負であることを示すことを意味します。(興味深いことに、すべての整数は標準形式で一意の有限表現を持っています。)

標準形式ではない表現は、次の観察を使用して常に標準形式に変換できます。

  1. 011 φ = 100 φ(なぜならφ 2 =φ+ 1)
  2. 0200 φ = 1001 φ(なぜならφ 2 + 1 /φ=2φ)
  3. 0〜10 φ = 101〜φ(なぜならφ - 1 /φ= 1)

加えて:

  1. 最上位桁が~1(残りの数値が標準形式である)場合、数値は負で1あり~1、すべてとを交換してマイナス記号を追加し、上記の3つの規則を再度適用することで標準形式に変換できます。標準フォームを入手します。

このような正規化の例を次に示します(各桁の位置を揃えるために、正の桁に追加のスペースを使用しています)。 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φ

さらに読むために、ウィキペディアには非常に有益な記事がありますにはトピックがあります。

チャレンジ

したがって、またはそうでなければ、(上記のように)小数を表す文字列が与えられると、先頭または末尾のゼロなしで標準形式を出力するプログラムまたは関数を作成します。入力には必ずしも小数点が含まれるわけではありませんが、常にその左側の数字が含まれます(したがって、.123)。出力には、常に小数点とその左側の少なくとも1桁が含まれている必要があります。

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
アーロン

回答:


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は、指定された変換を実行する関数を生成します。

それはゴルフにとって難しい問題です。コードの簡素化を妨げる多数のエッジケースが忍び寄っています。特に、解析と論理的処理の両方の面で、ネガを扱うのは苦痛です。

コードは「合理的な範囲」の入力のみを処理することに注意してください。関数の領域を無制限に拡張するには、ゼロの数を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直感では、任意の桁の入力を正規化するために必要なパスの数はとの間のどこかにnなりn log(n)ます。いずれの場合でも、パスの数は、追加されるすべての文字に対して10倍に増やすことができます。z定数のゼロの数も興味深い問題です。私は9では過剰であることが疑われる任意の可能な入力。
COTO 14

@MartinBüttner:ありがとう。文字クラスのエスケープを削除しました。に関しては$0、Javascriptはサポートしていません。または、少なくともFirefoxはサポートしていません。:P
COTO 14

OK 外側のループについては、whileループを作成する(または内側のforループに統合する)だけで、それ以上の変更が見つからない場合にブレークアウトする場合、それも必要ないと思います。私の仕様はその点で少し明確だったと思いますが、「原則として任意の(有効な)入力に対して正確で正確」ということは、唯一の理論上の制限は組み込みデータ型/ RAMのサイズであることを意味します。
マーティンエンダー14

1
@COTO 1バイトを節約するには、for( i = e = 0; i < n-3; i = j )byの最初の部分をfor(; i < n-3; i = j )移動して、宣言を先頭に移動して、N = t = n = 0;置き換えますN = t = n = i = e = 0;
Ismael Miguel 14

1
@IsmaelMiguel:のj値で一定に保持されていませんi+1。3つのifブロック内の通知jはにリセットされ0ます。したがって、最初のifブロックの後のどの時点でも、のプロキシとして使用することはできませんi+1。変数i自体はループの最後まで更新されません(ループ内の3番目のステートメントを使用for)。その値はループの最後まで使用されるためです。しかし、それを言って、多分私は何かを見逃している。コードを短くしてテストし、まだ機能することを確認できる場合は、pastebin.comにコピーを投稿し、こちらのリンクを投稿してください。私は答えであなたに正当な信用を拡張します。:)
COTO 14

2

Haskell、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]数値の+の(、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.