Jumlah atau perbedaan dua kekuatan dua


27

Tantangan Anda, jika Anda memilih untuk menerimanya, adalah, diberikan bilangan bulat K >= 1, temukan bilangan bulat non-negatif Adan B setidaknya satu dari dua syarat berikut ini berlaku:

  1. K = 2^A + 2^B
  2. K = 2^A - 2^B

Jika tidak ada Adan B, program Anda mungkin berperilaku dengan cara apa pun. (Untuk memperjelas, Adan Bbisa sama.)

Uji kasus

Seringkali ada beberapa solusi untuk suatu angka, tetapi berikut ini beberapa:

K => A, B
1 => 1, 0
15 => 4, 0                      ; 16 - 1 = 15
16 => 5, 4                      ; 32 - 16 = 16; also 3, 3: 8 + 8 = 16
40 => 5, 3                      ; 2^5 + 2^3 = 40
264 => 8, 3
17179867136 => 34, 11           ; 17179869184 - 2048 = 17179867136 

Kasing uji terakhir 17179867136,, harus berjalan di bawah 10 detik pada mesin yang relatif modern. Ini adalah kode golf, jadi program terpendek dalam byte menang. Anda dapat menggunakan program atau fungsi lengkap.


5
Bisakah A sama dengan B ?
Dennis

2
@ Dennis Saya tidak mengerti mengapa tidak.
Conor O'Brien

... dan untuk 16, keduanya 5,4dan 3,3valid.
Titus

Sebenarnya sekarang setelah saya pikirkan, bisakah A, Bmenjadi negatif? (mis. -1, -1untuk 1)
Sp3000

@ Sp3000 Tidak, poin bagus.
Conor O'Brien

Jawaban:


3

Jelly , 11 10 byte

;0+N&$BL€’

Menerapkan trik memutar-mutar sedikit dari jawaban Python oleh @xnor

Uji di TryItOnline
Semua kotak uji juga ada di TryItOnline

Bagaimana?

;0+N&$BL€’ - main link takes an argument, k, e.g 15
;0         - concatenate k with 0, e.g. [15, 0]
     $     - last two links as a monad
   N       - negate, e.g. -15
    &      - bitwise and, e.g. -15&15=1 since these two are called as a monad (one input)
  +        - add, vectorises, e.g. [16,1]
      B    - convert to binary, vectorises, e.g. [[1,0,0,0,0],[1]]
       L€  - length for each, e.g. [5,1]
         ’ - decrement, vectorises, e.g. [4,0]

15

Python 2, 43 byte

lambda n:[len(bin((n&-n)+k))-3for k in n,0]

Katakan itu n==2^a ± 2^bdengan a>b. Kemudian, faktor kekuatan-2 terbesar nadalah 2^b, dan kita bisa menemukannya menggunakan bit-trick 2^b = n&-n. Itu memungkinkan kita menghitung 2^b + n, yang sama dengan2^a + 2 * 2^b atau adil 2^a. Salah satu memiliki panjang bit yang sama panjangnya dengan a*. Jadi, kami menampilkan bit-lengths n&-ndan (n&-n)+n, dihitung dari panjang representasi binernya. Python 3 lebih panjang satu byte untuk parens di for k in(n,0)].

* Kecuali bahwa 2^a + 2^bdengan a==b+1memiliki panjang bit yang lebih panjang, tapi itu tidak masalah karena kita dapat mengartikannya sebagai 2^(a+1)-2^b.


Hebat - Saya mencari sedikit biola, tetapi tidak berhasil, hanya diangkut ke Jelly.
Jonathan Allan

Coba n=4atau 8atau 16tolong.
Titus

@Itus f(2**n)kembali (n+1,n)dan 2**(n+1)-2**n=2**ntidak ada masalah.
Jonathan Allan

ah ... Apa format bin()dalam Python?
Titus

@Itus itu adalah string dengan yang memimpin 0b, karenanya -3.
Jonathan Allan

8

JavaScript (ES6), 73 byte

(n,[s,f,z]=/^1+(.*1)?(0*)$/.exec(n.toString(2)))=>[s.length-!!f,z.length]

Untuk kasus pengurangan, angka pertama adalah jumlah digit dalam representasi biner dan angka kedua adalah jumlah trailing nol. Untuk kasus tambahan, kita kurangi 1 dari angka pertama. Jika representasi biner adalah semua 1s diikuti oleh beberapa 0s maka kasus tambahan diasumsikan sebaliknya diasumsikan kasus pengurangan. Port 36 byte versi @ xnor yang hanya berfungsi untuk B≤30 dalam JavaScript:

n=>[(l=Math.log2)(n+(n&=-n))|0,l(n)]

2
@ ETHproductions Tentu, tapi saya mainkan golf ke 36.
Neil

Buruk saya, saya berpikir bahwa versi 36-byte tidak bekerja untuk 17 miliar test case.
ETHproduksi

@ ETHproductions Tidak, tapi begitu juga port Anda, seingat saya (komentar sejak dihapus, desah), karena menggunakan operasi bitwise.
Neil

Maaf, ini dia lagi: n=>[n,0].map(k=>((n&-n)+k).toString(2).length-1)Dan kedua versi kembali [34,11]pada test case terakhir (Saya menggunakan FF 48).
ETHproduksi

@ EHProduksi Aha, jadi lebih akurat mereka bekerja ketika hasil kedua adalah 30 atau kurang.
Neil

6

Perl, 52 49 32 byte

Solusi lama (49 byte)

Termasuk +1 untuk -p

Berikan masukan pada STDIN:

pow2.pl <<< 17179867136

pow2.pl

#!/usr/bin/perl -p
$_=reverse sprintf"%b",$_;/()1(?:1+|0*)/;$_="@+"

Namun, menggunakan algoritma xnor dan menambahkan twist memberikan 32 byte:

perl -nE 'say 13/9*log|0for$;=$_&-$_,$_+$'

Hanya kode:

say 13/9*log|0for$;=$_&-$_,$_+$

Ini menderita kesalahan pembulatan parah karena 13/9 = 1.444...sedikit di atas 1/log 2 = 1.44269...( logitu sendiri juga memiliki kesalahan pembulatan tetapi itu jauh lebih kecil sehingga kita dapat membungkusnya dalam analisis 13/9). Tapi karena ada yang 2**big - 2** smalldiperbaiki 2** bigsebelum log ini tidak mater dan perhitungan untuk 2**big + 2 * 2**smallterpotong jadi juga aman .. Dan di sisi lain dari jangkauan 2**n+2**(n-1)tidak mendapatkan peningkatan yang cukup dalam kisaran [0,64](Saya tidak bisa dengan benar mendukung lebih dari rentang bilangan bulat karena penggunaan &) untuk mengarah pada hasil yang salah (multiplicator 1.5namun akan terlalu jauh untuk jumlah yang besar).


5

Brachylog , 23 byte

,A:B#+.:2rz:^a{+|-}?,.=

Cobalah online!

Ini jauh lebih cepat dari yang dibutuhkan, misalnya ini masih di bawah 10 detik pada TIO .

Penjelasan

Ini pada dasarnya adalah transkripsi langsung formula tanpa optimasi:

,A:B     The list [A, B]
#+       Both A and B are greater than or equal to 0
.        Output = [A, B]
:2rz     The list [[2, A], [2, B]]
:^a      The list [2^A, 2^B]
{+|-}?   2^A + 2^B = Input OR 2^A - 2^B = Input
,.=      Assign a value to A and B which satisfy those constraints

2
Sepertinya tantangan ini dibuat untuk bahasa: D
Conor O'Brien

4

Python, 69 byte

def f(k):b=bin(k)[::-1];return len(b)-2-(b.count('1')==2),b.find('1')

Tes ada di ideone

Karena input yang tidak valid dapat melakukan apa saja, kita tahu bahwa jika inputnya persis 2 bit, maka jumlah itu adalah jumlah dari 2 kekuatan 2, dan sebaliknya (jika valid) itu akan menjadi sejumlah bit yang dijalankan (termasuk kemungkinan hanya 1 bit) dan akan menjadi perbedaan antara kekuatan tertinggi berikutnya 2 dari MSB dan set LSB.


4

7 JAWA,142 ,140, 134 BYTES

Ini adalah posting pertama saya di PPCG! Saya akan sangat menghargai umpan balik tentang tips golf.
Terima kasih untuk membekukan karena menghemat 2 byte

void f(long n){for(int i=-1,j;i++<31;)for(j=0;j++<34;){long a=1,x=a<<i,y=a<<j;if(x+y==n|y-x==n){System.out.println(j+" "+i);return;}}}

UNGOLF

void f(long n){
    for(int i=-1,j;i++<31;)
         for(j=0;j++<34;){
          long a=1,x=a<<i,y=a<<j;
            if(x+y==n|y-x==n){
            System.out.println(j+" "+i);
        return;
        }
            }
    }

ideone


1
Hai, angkaknot! Pengembara lain dari kebingungan saya melihat. Tampaknya tidak berhasil 40=2**3+2**5, misalnya. Melihat itu, saya tidak bisa melihat mengapa tidak, mungkin saya membuat kesalahan transkripsi ...
Jonathan Allan

1
@JonathanAllan Sekarang berfungsi dengan baik. Sebenarnya tanda kurung tidak ada di baris ini jika ((a << i) + (a << j) == n | (a << j) - (a << i) == n ) dan terimakasih.
Numberknot

Tidak bisakah Anda menggunakan literal 1alih-alih mendeklarasikan variabel untuknya?
Titus

1
@ ISus jika saya menggunakan literal 1 maka testcase ini (17179867136) tidak akan mungkin karena jika Anda menggunakan literal 1 maka java secara otomatis menetapkannya sebagai ruang memori INT.
Numberknot

1
Anda dapat mendeklarasikan j bersama dengan saya:for(int i=-1,j;[...]
Frozn

4

Mathematica, 57 54 byte

Disimpan 3 byte berkat LegionMammal978!

Do[Abs[2^a-#]==2^b&&Print@{a,b},{a,2Log@#+1},{b,0,a}]&

Sebenarnya mencetak semua 1 pasangan yang sesuai {a, b}. 2Log@#+1adalah batas atas untuk terbesar ayang mungkin dapat muncul saat mewakili input #(batas atas ketat adalah Log [2 #] / Log [2] = 1,44 ... Log [#] + 1). Berjalan hampir seketika pada input uji, dan dalam waktu kurang dari seperempat detik (pada komputer saya yang baru tetapi tidak tersedia) pada input 100 digit.

1 Membiarkan amulai dengan nilai default 1 bukannya 0 menghemat dua byte; itu menyebabkan output {0,0} dilewatkan ketika input 2, tetapi menemukan output {2,1} dalam kasus itu, yang cukup baik.


Semua * pasangan yang tepat? (Juga, If[Abs[2^a-#]==2^b,Print@{a,b}]dapat diganti dengan Abs[2^a-#]==2^b&&Print@{a,b}untuk menyimpan 3 byte.)
LegionMammal978

Pengamatan yang bagus, saya mengerti! "Semua *" adalah catatan kaki, tetapi sekarang lebih jelas.
Greg Martin

3

MATL , 23 22 byte

BnQ:qWtG-|ym)1)tG-|hZl

Cobalah online! Atau verifikasi semua kasus uji .

Penjelasan

B      % Implicit input. Convert to binary. Gives n digits
nQ:q   % Range [1 ... n+1]
W      % 2 raised to that, element-wise: gives [1 2 4 ... 2^(n+1)] (*)
tG-|   % Duplicate. Absolute difference with input, element-wise (**)
y      % Push a copy of (*)
m      % True for elements of (**) that are members of (*)
)      % Use as logical index to select elements from (*)
1)     % Take the first element. Gives power of the first result
tG-|   % Duplicate. Absolute difference with input. Gives power of the second result
hZl    % Concatenate. Take binary logarithm. Implicit display

3

Perl 6 , 41 byte

{.base(2).flip~~/1[1+|0*]/;$/.to,$/.from}

(Algoritma disalin tanpa malu-malu dari jawaban Perl 5 )

Penjelasan:

# bare block lambda with implicit parameter 「$_」
{
  # turn into binary
  # ( implicit method call on 「$_」 )
  .base(2)

  # flip the binary representation
  .flip

  ~~ # smartmatch that against:

  /
    1      # a 「1」
    [
      | 1+ # at least one 「1」
      | 0* # or any number of 「0」
    ]
  /;

  # returns a list comprised of

  # the position of the end of the match (larger of the two)
  $/.to,
  # the position of the beginning of the match
  $/.from
}

Pemakaian:

# give it a lexical name for clarity
my &bin-sum-diff = {.base(2).flip~~/1[1+|0*]/;$/.to,$/.from}

say bin-sum-diff 15; # (4 0)
say bin-sum-diff 16; # (5 4)

say bin-sum-diff 20; # (4 2)
# 2**4==16, 2**2==4; 16+4 == 20

say bin-sum-diff 40; # (5 3)
say bin-sum-diff 264; # (8 3)
say bin-sum-diff 17179867136; # (34 11)

1

PHP, 73 byte

Saya bisa menyalin solusi Jonathan Pyhton 2 untuk 54 byte (+13 overhead),
tetapi ingin datang dengan sesuatu yang berbeda.

simpan ke file, lalu jalankan dengan phpatau php-cgi.

<?=strlen($n=decbin($argv[1]))-!!strpos($n,'01')._.strpos(strrev($n),49);

cetakan adanb dipisahkan oleh garis bawah, apa pun tanpa solusi.

solusi khas, 96 byte

<?=preg_match('#^(10*1|(1+))(0*)$#',decbin($argv[1]),$m)?strlen($m[0])-!$m[2]._.strlen($m[3]):_;

cetakan adanb dipisahkan oleh garis bawah; satu-satunya garis bawah tanpa solusi.

Bahkan memberi tahu Anda operasi untuk 11 byte lebih:
Cukup ganti garis bawah pertama dalam kode dengan '-+'[!$m[2]].


Jika saya mencoba 67 dalam echo strlen ($ n = decbin ($ argv [1])) - !! strpos ($ n, '01 ') .'- +' [! $ N [2]]. Strpos (strrev ( $ n), 49); itu memberi saya kembali 6 + 0 yaitu 65
Jörg Hülsermann

@ JörgHülsermann: 67 tidak punya solusi; perilaku tanpa solusi tidak ditentukan; jadi tidak masalah apa yang dicetak untuk 67.
Titus

0

PHP, 117 Bytes

if(preg_match("#^(1+|(10*1))0*$#",$b=decbin($k=$argv[1]),$t))echo($l=strlen($b))-($t[2]?1:0).",",$l+~strrpos($b,"1");

Versi diperpanjang 4 Kasus

$l=strlen($b=decbin($k=$argv[1]));
// Case 1: n=2(n-1)=n+n or n=n*(2-1)=2n-n 
if(preg_match('#^100*$#',$b))echo($l-2).'a+'.($l-2).':'.$l.'a-'.($l-1);
// Case 2: n-m
elseif(preg_match('#^1+0*$#',$b)){echo $l.'b-',strpos($b,"0")?$l-strpos($b,"0"):0;}
// Case 3: n+m 
elseif(preg_match('#^10*10*$#',$b))echo ($l-1).'c+',$l-strrpos($b,"1")-1;
else echo "Nothing";

serikat versi pendek Kasus 1 dan 3 dan membuat Perbedaan ke Kasus 3 dan di kedua versi Kasus 4 tidak menghasilkan output.

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.