範囲内の最短の2進数


8

二つの与えられた任意の正確な数0≤ X < Y ≤1、(桁)最短計算バイナリBように、XB < yと

2進小数点の後のbの2進数を、配列またはゼロと1の文字列として出力します。空の配列は、末尾のゼロを削除することにより、0.0を意味することに注意してください。これはまた、どの範囲にも固有の正解があることを確認します。

2進数の小数に慣れていない場合は、10進数と同じように機能します。

Base 10   0.625 = 0.6 + 0.02 + 0.005 = 6 x 10^-1  +  2 x 10^-2  +  5 x 10^-3
Base  2   0.101 = 0.1 + 0.00 + 0.001 = 1 x  2^-1  +  0 x  2^-2  +  1 x  2^-3
                                          |             |             |
                                          v             v             v
Base 10                        0.625 =   0.5      +     0       +   0.125

この問題を簡単にするビルトインは許可されていません。

例:

0.0, 1.0 -> ""
0.1, 1.0 -> "1"
0.5, 0.6 -> "1"
0.4, 0.5 -> "0111"

最短のコードが勝ちます。


3
「任意に正確」とは、「言語のタイプの制限内」を意味するの(0.98983459823945792125172638374187268447126843298479182647, 0.98983459823945792125172638374187268447126843298479182648)ですか、それとも、の入力をサポートする必要がありますか?また、テストケースも役立ちます。
ドアノブ

@Doorknob任意に正確とは、物理マシン(メモリ)の制限まで、あらゆる入力に対して回答が機能することを意味します。つまり、その入力はサポートされている必要があります。
orlp 2016


@MartinBüttner本当に近い(気づかなかった)が、この質問には任意の精度とビットとしての出力が必要です。
orlp 2016

1
ああ、上半分の開いた間隔x≤b <yは扱いにくいです、それはx <b≤yでとても簡単でしょう。
xnor 2016

回答:


2

CJamさん、46歳

q'.-_,:M;S/{3a.+M'0e]~GM#*AM(#/(2b}/_@.=0#)<2>

オンラインでお試しください

説明:

一般的な考え方は、両方の数値に10を掛けて整数を得るのに十分な大きさの指数、2を掛けて整数の形式の2進数の「余地を作る」のに十分な指数を掛け、最初の指数を 10で整数除算し、数値( "x <b≤y"の場合)と結果を基数2に変換します。最初の異なる数字を見つけ(最初の数字は0、2番目の数字は1)、すべての数字を出力します2番目の数からその数まで。

乗算を始める前に、デクリメント後の結果のバイナリ桁数が同じ(先行ゼロなし)になるように、整数部分に3を追加します。最後に、補正するために最初の2桁の2桁をスキップしています。

q          read the input as a string
'.-        remove the dots
_,         duplicate and get the string length
:M;        store in M and pop; M-1 will be the first exponent
S/         split by space
{…}/       for each number (in string form)
  3a.+     add 3 to the first digit (vectorized-add [3] to the string)
  M'0e]    pad to the right with '0's up to length M
            this is like multiplying the decimal number with 10^(M-1)
            but done as a string operation
  ~        evaluate the result as an integer
  GM#*     multiply by 16^M (G=16) = 2^(4*M) -- 4*M is the second exponent
  AM(#/    divide by 10^(M-1) (A=10)
  (2b      decrement and convert to base 2 (array of digits)
_          duplicate the 2nd array
@          bring the first array to the top
.=         vectorized-compare the arrays (digit by digit)
0#         find the position of the first 0 (meaning digits are not equal)
)<         increment and slice the other copy of the 2nd array before that position
2>         discard the first 2 digits

2

Ruby、138132バイト

->x,y{d,*a=->{a.map.with_index{|n,i|n/BigDecimal.new(2)**(i+1)}.inject(:+)||0};[a+=[1],a[-1]=d[]>=y ?0:1]while d[]<x;a}

-rbigdecimalフラグ用に13バイトが追加されました。入力が2つBigDecimalのであることを期待しています。

サンプルの実行:

irb(main):029:0> f=->x,y{d,*a=->{a.map.with_index{|n,i|n/BigDecimal.new(2)**(i+1)}.inject(:+)||0};[a+=[1],a[-1]=d[]>=y ?0:1]while d[]<x;a}
=> #<Proc:0x00000001053a10@(irb):29 (lambda)>
irb(main):030:0> f[BigDecimal.new('0.98983459823945792125172638374187268447126843298479182647'),BigDecimal.new('0.98983459823945792125172638374187268447126843298479182648')]
=> [1, 1, 1, 1, 1, 1, 0, 1, 0, 1, 1, 0, 0, 1, 0, 1, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 1, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 0, 1, 0, 0, 0, 1, 0, 0, 1, 1, 1, 1, 0, 1, 0, 0, 1, 1, 1, 1, 0, 1, 0, 0, 1, 1, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 0, 0, 1, 1, 1, 1, 0, 1, 0, 1, 1, 0, 0, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 1, 1, 0, 0, 0, 0, 1, 0, 1, 1, 1, 0, 0, 0, 0, 0, 1, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 0, 1, 0, 1, 1, 0, 1, 1, 0, 1, 0, 0, 1, 1, 1]

説明:

->x,y{
d,*a=   # sets d to the following, and a to [] with fancy splat operator
->{     # lambda...
 a.map.with_index{|n,i|       # map over a with indices
  n/BigDecimal.new(2)**(i+1)  # this will return:
                              #  - 0 [ /2**(i+1) ] if n is 0
                              #  - 1   /2**(i+1)   if n is 1
 }.inject(:+)                 # sum
 ||0                          # inject returns nil on empty array; replace with 0
};      # this lambda turns `[0, 1, 1]' into `BigDecimal(0b0.011)'
[       # `[...]while x' is a fancy/golfy way to say `while x;...;end'
 a+=[1],            # add a digit 1 to the array
 a[-1]=d[]>=y ?0:1  # replace it with 0 if we exceeded upper bound
]while d[]<x;       # do this while(below the lower bound)
a       # return the array of digits
}

2

Mathematica、72バイト

IntegerDigits[#2[[-1,-1]],2,Log2@#]&@@Reap[1//.a_/;Sow@⌈a#⌉>=a#2:>2a]&

説明

その方法は2^n、整数を含むように2つの入力数値間のギャップを拡大する最小の乗数を見つけることです。

たとえば、16*{0.4,0.5} = {6.4,8.}はを含む7ので、答えは7/16です。

テストケース

%[0.4,0.5]
(* {0,1,1,1} *)

素敵な刈り取りと種まき!
シモンズ

0

JavaScript(ES6)、144バイト

f=(x,y,b='',d=s=>s.replace(/\d/g,(n,i)=>(i&&n*2%10)+(s[i+1+!i]>4)).replace(/[.0]+$/,''),n=d(x),m=d(y))=>n?n>'1'||(m||2)<='1'?f(n,m,b+n[0]):b+1:b

フォームへの入力を想定します0.<digits>(または1.<zeros>で許容されますy)。d数値の小数部を取り、それを2倍にして、末尾のゼロを削除する関数です。先頭桁は存在する必要がありますが、無視されます。便利d("0.0")なことに、空なので、これはがx正確な2進分数であるかどうかを確認するためのテストとして使用されます。この場合b、結果はすでに保持されています。それ以外の場合、a 1に接尾辞を付けることでとbを区別できるかどうかを判断するためのやや複雑なテストがxありyます。もしそうならそれが返されます。それ以外の場合、MSBのx末尾に結果が追加され、関数はそれ自体を再帰的に呼び出して次のビットを処理します。

代わりにx < b ≤ y、関数をもっと単純にしたい場合は、次のようになります(テストされていません)。

f=(x,y,b='',d=s=>s.replace(/\d/g,(n,i)=>(i&&n*2%10)+(s[i+1+!i]>4)),n=d(x),m=d(y))=>n>='1'||m<'1'?f(n,m,b+n[0]):b+1
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.