Radice quadrata intera di intero [chiuso]


12

Problema:

Nella scelta della lingua, scrivi la funzione più breve che restituisce il piano della radice quadrata di un numero intero a 64 bit senza segno.

Casi test:

La tua funzione deve funzionare correttamente per tutti gli input, ma qui ci sono alcuni che aiutano a illustrare l'idea:

               INPUT ⟶ OUTPUT

                   0 ⟶  0
                   1 ⟶  1
                   2 ⟶  1
                   3 ⟶  1
                   4 ⟶  2
                   8 ⟶  2
                   9 ⟶  3
                  15 ⟶  3
                  16 ⟶  4
               65535 ⟶ 255
               65536 ⟶ 256
18446744073709551615 ⟶ 4294967295

Regole:

  1. Puoi nominare la tua funzione come preferisci. (Le funzioni senza nome, anonime o lambda vanno bene, purché siano in qualche modo richiamabili.)
  2. Il conteggio dei personaggi è ciò che conta di più in questa sfida, ma anche il runtime è importante. Sono sicuro che potresti scansionare iterativamente verso l'alto per la risposta in tempo O (√n) con un conteggio di caratteri molto piccolo, ma il tempo O (log (n)) sarebbe davvero migliore (cioè assumendo un valore di input di n, non una lunghezza di bit di n).
  3. Probabilmente vorrai implementare la funzione usando solo numeri interi e / o artitmetici booleani. Tuttavia, se vuoi davvero usare i calcoli in virgola mobile, allora va bene finché non chiami funzioni di libreria. Quindi, dire semplicemente return (n>0)?(uint32_t)sqrtl(n):-1;in C è off limits anche se produrrebbe il risultato corretto. Se stai usando aritmetica in virgola mobile, è possibile utilizzare *, /, +, -, e elevamento a potenza (ad esempio, **o ^se si tratta di un built-in operatore in lingua di propria scelta, ma l'elevazione a potenza solo di poteri non inferiore a 1 ). Questa limitazione serve a prevenire "imbrogli" chiamando sqrt()o una variante o aumentando un valore a ½ potenza.
  4. Se si utilizzano operazioni in virgola mobile (vedere # 3), non è necessario che il tipo restituito sia intero; solo che il valore restituito è un numero intero, ad esempio, floor (sqrt (n)), ed essere in grado di contenere qualsiasi valore a 32 bit senza segno.
  5. Se si utilizza C / C ++, è possibile supporre l'esistenza di tipi interi senza segno a 64 e 32 bit, ad esempio uint64_te uint32_tcome definito in stdint.h. Altrimenti, assicurati solo che il tuo tipo intero sia in grado di contenere qualsiasi numero intero senza segno a 64 bit.
  6. Se il tuo langauge non supporta numeri interi a 64 bit (ad esempio, Brainfuck apparentemente ha solo il supporto numeri interi a 8 bit), fai del tuo meglio con quello e indica la limitazione nel titolo della risposta. Detto questo, se riesci a capire come codificare un numero intero a 64 bit e ottenerne correttamente la radice quadrata usando l'aritmetica primitiva a 8 bit, allora più potenza per te!
  7. Divertiti e diventa creativo!

7
"ma O (log₄ (n)) il tempo sarebbe davvero meglio." - molto meglio? C'è un bonus? È un requisito difficile? È essenzialmente una sfida separata? È solo una bella idea che non influisce sul punteggio?
John Dvorak,

3
Normalmente si usa la dimensione dell'input piuttosto che il valore dell'input per derivare la complessità algoritmica. In tal senso, l'algoritmo di incremento e ripetizione ha una velocità esponenziale.
John Dvorak,

3
Umm ... O(log_2 n) === O(log_4 n). log_4(n) = log_2(n) / log_2(2) = log_2(n) / 2
John Dvorak,

1
Conta 2/4?
Milo,

1
La maggior parte dei tipi di dati in virgola mobile non ha comunque la precisione necessaria per questa attività. 53 bit significativi non sono sufficienti per l'intero intervallo di input.
user2357112 supporta Monica il

Risposte:


14

CJam, 17 (o 10) byte

{_1.5#\/i}

Provalo online verificando i casi di test:

[0 1 2 3 4 8 9 15 16 65535 65536 18446744073709551615]{_1.5#\/i}%N*

Non supererà l'ultimo caso di test a causa di problemi di arrotondamento, ma poiché 18446744073709551615non è un numero intero in CJam (è un numero intero grande ), siamo ancora bravi, giusto?

In caso contrario, il codice seguente (e leggermente più lungo) correggerà tali errori:

{__1.5#\/i_2#@>-}

Non è più la soluzione più breve, ma faaast .

Come funziona

__    " Duplicate the integer twice. ";
1.5#  " Raise to power 1.5. Note that, since 1.5 > 1, this doesn't break the rules. ";
\     " Swap the result with the original integer. ";
/     " Divide. ";
i     " Cast to integer. ";
_2#   " Push square of a copy. ";
@     " Rotate the orginal integer on top of the stack. ";
>-    " If the square root has been rounded up, subtract 1. ";

Hahaha! oops, ok, mi hai preso un tecnicismo lì. Non avrei dovuto dire poteri frazionari. Ma il tuo codice obbedisce davvero alle regole dichiarate, quindi lo sto votando. :)
Todd Lehman,

2
CJam ha decimali di precisione arbitraria, per coprire l'intero intervallo di input?
isaacg,

Inoltre, un bel trucco di usare NaN -> 0 su cast per int.
isaacg,

Idea pulito, può anche essere rappresentato in J nello stesso identico numero di caratteri: <.@%~^&1.5. Posso pubblicare questo come una risposta separata (dal momento che è fondamentalmente una tua porta esatta)?
ɐɔıʇǝɥʇuʎs,

@ ɐɔıʇǝɥʇuʎs: vai avanti. Ma ho appena capito che la mia soluzione potrebbe arrotondare in modo errato per grandi numeri, incluso l'ultimo caso di test. A mia difesa, ha superato la mia ispezione solo perché 4294967295e 4294967296sembra molto simile ...
Dennis

10

Haskell, 28 26

Credo che questa sia la voce più breve da qualsiasi lingua non progettata per il golf.

s a=[x-1|x<-[0..],x*x>a]!!0

Denomina una funzione scon parametro ae restituisce meno un primo numero il cui quadrato è maggiore di a. Corre incredibilmente lentamente (O (sqrt n), forse?).


1
Un indice elenco ( [...]!!0) non sarebbe più corto di head?
Isaacg,

@isaacg Sì, lo sarebbe. Grazie :-)
Zaq,

7

Golfscript, 17 caratteri

{).,{.*1$<},,\;(}

Potrei nominare la mia funzione come mi piaceva, ma ho deciso di non nominarla affatto. Aggiungi due caratteri per nominarlo, aggiungine tre per nominarlo e non lasciarlo in pila, sottrai un carattere se fornire un programma completo è OK.

Questo abominio non corre nel tempo logaritmico nel valore dell'input, non nel tempo O (sqrt n), ci vuole un tempo lineare enorme per produrre il risultato. Ci vuole anche molto spazio. Assolutamente orrendo. Ma ... questo è code-golf.

L'algoritmo è:

n => [0..n].filter(x => x*x < n+1).length - 1

Lo adoro!! Bel lavoro! È meravigliosamente perverso.
Todd Lehman,

7

Pyth , 14 caratteri

DsbR;fgb*TTL'b

Fornisce una funzione denominata, che calcola la radice quadrata filtrando l'elenco da 0 a n perché il quadrato è più grande dell'input, quindi stampa l'ultimo numero. Non usa esponenziazione o galleggianti.

Dsb       def s(b):
R;        return last element of
f         filter(lambda T:
gb*TT                     b>=T*T,
L'b                       range(b+1))

Esempio di utilizzo:

python3 pyth.py <<< "DsbR;fgb*TTL'b       \msd[0 1 2 3 4 8 9 15 16 65535 65536"
[0, 1, 1, 1, 2, 2, 3, 3, 4, 255, 256]

7

Retina (non competitiva - La lingua è più recente della sfida), 43

Mentre lavoravo su questa risposta , mi è venuto in mente che un metodo simile può essere usato per calcolare le radici quadrate intere usando la retina:

.+
$*
^
1:
+`(1+):(11\1)
1 $2:
1+:$|:1+

1+

Ciò si basa sul fatto che i quadrati perfetti possono essere espressi come 1+3+5+7+..., e per corollario, che il numero di termini in questa espressione è la radice quadrata.

Provalo online. (Prima riga aggiunta per consentire l'esecuzione di più testcase.)

Ovviamente a causa della conversione da decimale a unaria, questo funzionerà solo per input relativamente piccoli.


4
(La lingua è più recente della sfida)
mbomb007,

@ mbomb007 Abbastanza giusto - Titolo modificato. Questa risposta è sicuramente nella categoria "perché può essere fatta" e non intende competere nella sfida in alcun modo significativo.
Digital Trauma,


6

Perl, 133 caratteri

Di gran lunga non il più breve, ma utilizza un algoritmo cifra per cifra per gestire input di qualsiasi dimensione e viene eseguito nel tempo O (log n). Converte liberamente tra numeri come stringhe e numeri come numeri. Poiché il prodotto più grande possibile è il root-finora con il quadrato di una singola cifra, dovrebbe essere in grado di prendere la radice quadrata di circa 120-bit circa su un sistema a 64-bit.

sub{($_)=@_;$_="0$_"if(length)%2;$a=$r="";while(/(..)/g){
$a.=$1;$y=$d=0;$a<($z=$_*(20*$r+$_))or$y=$z,$d=$_ for 1..9;$r.=$d;$a-=$y}$r}

Decompresso, ovvero:

sub {
  my ($n) = @_;
  $n = "0$n" if length($n) % 2; # Make an even number of digits
  my ($carry, $root);
  while ($n =~ /(..)/g) { # Take digits of $n two at a time
    $carry .= $1;         # Add them to the carry
    my ($product, $digit) = (0, 0);
    # Find the largest next digit that won't overflow, using the formula
    # (10x+y)^2 = 100x^2 + 20xy + y^2 or
    # (10x+y)^2 = 100x^2 + y(20x + y)
    for my $trial_digit (1..9) {
      my $trial_product = $trial_digit * (20 * $root + $trial_digit);
      if ($trial_product <= $carry) {
        ($product, $digit) = ($trial_product, $trial_digit);
      } 
    } 
    $root .= $digit;
    $carry -= $product;
  } 
  return $root;
}

Bello! Mi chiedevo quando qualcuno avrebbe postato una risposta Perl. A proposito, funziona if length%2invece di dire if(length)%2? Sarebbe rasato 1 personaggio. Inoltre, avrebbe funzionato dire $y=$z,$d=$_ ifinvece di ($y,$d)=($z,$_)if? Penso che raderebbe altri 3 personaggi.
Todd Lehman,

E questo sta diventando un po 'perverso, ma penso che puoi rasartene ancora 1 riscrivendo il forloop come:$a<($z=$_*(20*$r+$_))or$y=$z,$d=$_ for(1..9);
Todd Lehman,

Il primo suggerimento non funziona (cerca di prendere la lunghezza di un hash denominato %2), ma gli altri sono validi. Li lavorerò dentro.
Hobbs,

1
@ToddLehman postfix fornon ha bisogno di parentesi; aggiungendo questo ai tuoi suggerimenti, mi vengono aggiunti 6 caratteri in totale. Grazie!
Hobbs,

5

Matlab (56) / Octave (55)

Risolve la radice quadrata usando un metodo a punto fisso. Converge in massimo 36 passi (per 2 ^ 64-1 come argomento) e quindi controlla se è la più bassa delle radici di numeri interi "possibili". Poiché utilizza sempre 36 iterazioni, ha una durata di O (1) = P

Si presume che l'argomento sia uint64.

MATLAB:

function x=q(s)
x=1
for i = 1:36
    x = (x+s/x)/2
end
if x*x>s
    x=x-1
end

Ottava:

function x=q(s)
x=1
for i = 1:36
    x = (x+s/x)/2
end
if x*x>s
    x-=1
end

Questo è un nuovo metodo per me, e sembra essere piuttosto interessante. +1
seequ,

1
È fondamentalmente il en.wikipedia.org/wiki/… che è uno dei primi metodi numerici conosciuti che si stima abbia circa 3700 anni. Può essere giustificato da en.wikipedia.org/wiki/Banach_fixed-point_theorem che ha una prova sorprendentemente facile, è davvero bello =)
flawr,

5

Rubino - 36 caratteri

s=->n{g=n;g=(g+n/g)/2 while g*g>n;g}

Ben fatto! Qual è il tempo di esecuzione nel caso peggiore?
Todd Lehman,

Che dire nel caso in cui g * g <n e la risposta non siano ancora vicini al valore desiderato? La sceneggiatura non si fermerà?
WallyWest,

1
@ToddLehman Sinceramente non lo so. : - / Questo è il metodo babilonese . Ecco cosa sembra essere una buona prova della complessità media . L'ipotesi iniziale del numero stesso è piuttosto negativa, ma avrei bisogno di sedermi e cercare davvero quella prova per capire il caso peggiore. Ci proverò quando avrò più tempo libero. :-)
OI,

@WallyWest La mia comprensione è che il whileloop termina esattamente quando g converge a floor (√n) che è il valore desiderato. Vedi qualche caso in cui ciò non sarebbe vero?
OI,

4

Python (39)

f=lambda n,k=0:k*k>n and k-1or f(n,k+1)

L'approccio ricorsivo naturale. Conta le potenziali radici quadrate fino a quando il loro quadrato è troppo alto, quindi scende di 1. Usa Stackless Python se sei preoccupato di superare la profondità dello stack.

Il and/orlinguaggio è equivalente all'operatore ternario come

f=lambda n,k=0:k-1 if k*k>n else f(n,k+1)

Edit: posso invece ottenere 25 caratteri sfruttando la regola "si può utilizzare *, /, +, -, e elevamento a potenza (ad esempio, **o ^se si tratta di un elevamento a potenza di operatore incorporato nella lingua di propria scelta, ma solo di poteri non inferiore a 1). " (Modifica: Apparentemente Dennis ha già trovato e sfruttato questo trucco.)

lambda n:n**1.5//max(n,1)

Uso l'operatore divisione intera //di Python 3 per arrotondare per difetto. Sfortunatamente, spendo molti personaggi per n=0non dare una divisione per errore 0. Se non fosse per questo, potrei fare 18 caratteri

lambda n:n**1.5//n 

Le regole inoltre non dicevano che la funzione dovesse essere nominata (a seconda del modo in cui interpreti "Puoi nominare la tua funzione come preferisci"), ma se lo fa, sono altri due caratteri.


- Grazie, lo chiarirò. Deve solo essere una funzione. Non deve essere nominato. Quindi, le funzioni lambda vanno bene. Lo avrei menzionato dall'inizio se ci avessi pensato. Stavo pensando troppo in termini di C quando ho pubblicato la domanda.
Todd Lehman,

4

C99 (58 caratteri)

Questo è un esempio di risposta che non considererei valida, anche se per me è interessante dal punto di vista del golf code perché è così perverso, e ho pensato che sarebbe stato divertente buttare nel mix:

Originale: 64 caratteri

uint64_t r(uint64_t n){uint64_t r=1;for(;n/r/r;r++);return r-1;}

Il motivo per cui questo è terribile è che funziona nel tempo O (√n) piuttosto che nel tempo O (log (n)). (Dove n è il valore di input.)

Modifica: 63 caratteri

Modifica del r-1a --re confinamento in return:

uint64_t r(uint64_t n){uint64_t r=1;for(;n/r/r;r++);return--r;}

Modifica: 62 caratteri

Spostamento dell'incremento del loop all'interno della porzione condizionale del loop (nota: questo ha un comportamento non garantito perché l'ordine delle operazioni rispetto all'operatore di preincremento è specifico del compilatore):

uint64_t r(uint64_t n){uint64_t r=0;for(;n/++r/r;);return--r;}

Modifica: 60 caratteri

Aggiunta di a typedefper nascondere uint64_t(credito all'utente technosaurus per questo suggerimento).

typedef uint64_t Z;Z r(Z n){Z r=0;for(;n/++r/r;);return--r;}

Modifica: 58 caratteri

Ora richiede che il secondo parametro venga passato come 0 nell'invocazione della funzione, ad esempio, r(n,0)anziché solo r(n). Ok, per la mia vita, a questo punto non riesco a vedere come comprimerlo ulteriormente ... nessuno?

typedef uint64_t Z;Z r(Z n,Z r){for(;n/++r/r;);return--r;}

Se siete disposti a chiamarlo C ++ e decremento piuttosto che di incremento si sarebbe in grado di radere al largo un paio di caratteri: uint64_t s(uint64_t n){for(uint64_t r=n;--n>r/n;);return n;}.
Fors,

@Fors - Bel approccio! Sfortunatamente, ciò non causerà una divisione per zero per l'ingresso di 1? Inoltre, cosa farà per un input di 0? Perché --nquando n==0sarebbe –1 e questi sono valori senza segno, quindi –1 sarebbe 2⁶⁴ – 1.
Todd Lehman,

1
#define Z uint64_t ... o typedef salverà un paio
technosaurus

@technosaurus - Ah sì, questo fa risparmiare 2. Grazie. :-)
Todd Lehman,

1
L'espressione n/++r/rha un comportamento indefinito ....
aschepler

4

Golfscript - 14 caratteri

{.,\{\.*<}+?(}

Trova il numero più piccolo in imeno dell'input nper il quale n < i*i. Ritorno i - 1.

ie [0..n-1].first(i => n < i*i) - 1

Spiegazione per coloro che non conoscono anche Golfscript, per una chiamata di esempio con input 5:

.        //Duplicate input.  Stack: 5 5
,        //Get array less than top of stack.  Stack: 5 [0 1 2 3 4]
\        //Switch top two elements of stack.  Stack: [0 1 2 3 4] 5
{\.*<}+  //Create a block (to be explained), and prepend the top of the stack.  
         //Stack: [0 1 2 3 4]{5\.*<}
?        //Find the first element of the array for which the block is true. 
         //So, find the first element of [0 1 2 3 4] for which {5\.*<} evaluates to true.
         //The inner block squares a number and returns true if it is greater than the input.
(        //Decrement by 1 

Ooh, sono 3 caratteri più brevi della precedente migliore risposta Golfscript. Bel lavoro!
Todd Lehman,

Risolvere questo problema per fornire la risposta corretta per l'input 1richiede probabilmente due caratteri.
Peter Taylor,

4

Haskell, 147 138 134 128 byte

Non è il codice più breve al mondo, ma funziona in O (log n) e su numeri di dimensioni arbitrarie:

h x=div(x+1)2
n%(g,s)|g*g<n=(g+s,h s)|g*g>n=(g-s,h s)|0<1=(g,0)
f(x:r@(y:z:w))|x==z=min x y|0<1=f r
s n=fst$f$iterate(n%)(n,h n)

Ciò esegue una ricerca binaria dell'intervallo [0..n] per trovare la migliore approssimazione inferiore a sqrt (n). Ecco una versione non golfata:

-- Perform integer division by 2, rounding up
half x = x `div` 2 + x `rem` 2

-- Given a guess and step size, refine the guess by adding 
-- or subtracting the step as needed.  Return the new guess
-- and step size; if we found the square root exactly, set
-- the new step size to 0.
refineGuess n (guess, step)
    | square < n  =  (guess + step, half step)
    | square > n  =  (guess - step, half step)
    | otherwise   =  (guess, 0)
    where square = guess * guess     

-- Begin with the guess sqrt(n) = n and step size (half n),
-- then generate the infinite sequence of refined guesses.
-- 
-- NOTE: The sequence of guesses will do one of two things:
--         - If n has an integral square root m, the guess 
--           sequence will eventually be m,m,m,...
--         - If n does not have an exact integral square root,
--           the guess sequence will eventually alternate
--           L,U,L,U,.. between the integral lower and upper
--           bounds of the true square root.
--        In either case, the sequence will reach periodic
--        behavior in O(log n) iterations.
guesses n = map fst $ iterate (refineGuess n) (n, half n)

-- Find the limiting behavior of the guess sequence and pick out
-- the lower bound (either L or m in the comments above)
isqrt n = min2Cycle (guesses n)
    where min2Cycle (x0:rest@(x1:x2:xs))
            | x0 == x2    =   min x0 x1
            | otherwise   =   min2Cycle rest

Modifica: salvato due byte sostituendo le clausole "altrimenti" con "0 <1" come versione più corta di "Vero" e qualche altro inserendo g * g.

Inoltre, se sei soddisfatto di O (sqrt (n)), potresti semplicemente farlo

s n=(head$filter((>n).(^2))[0..])-1

per 35 personaggi, ma che divertimento è?

Modifica 2: Mi sono appena reso conto che poiché le coppie sono ordinate per ordine del dizionario, invece di fare min2Cycle. mappa prima, posso solo fare prima. min2Cycle. Nel codice golf, ciò si traduce nella sostituzione di f $ map fst con fst $ f, risparmiando altri 4 byte.

Modifica 3: salvato altri sei byte grazie a proudhaskeller!


1
puoi sostituire (div x 2 + rem x 2) con div (x + 1) 2, alla tua funzione "metà"
orgoglioso haskeller il

In realtà ho una mia soluzione che ha 49 caratteri e risolve in O (log n), ma ho solo 2 voti ;-(. Non capisco perché
orgoglioso haskeller

4

JavaScript 91 88 86: ottimizzato per la velocità

function s(n){var a=1,b=n;while(Math.abs(a-b)>1){b=n/a;a=(a+b)/2}return Math.floor(a)}

JavaScript 46: non ottimizzato per la velocità

function s(n){a=1;while(a*a<=n)a++;return a-1}

Ecco un JSFiddle: http://jsfiddle.net/rmadhuram/1Lnjuo4k/


1
Benvenuti in PPCG! Puoi usare <s> 91 </s> <s> 88 </s> per barrare. Ho provato a fare la modifica ma tu stavi modificando allo stesso tempo, quindi ti lascerò fare.
Rainbolt

1
Oppure potresti farlo in 41 caratteri come questo:function s(n){for(a=1;++a*a<n;);return a}
Crema di rabarbaro

4

C 95 97

Modifica Typedef, suggerito da @Michaelangelo

Questa dovrebbe essere più o meno un'implementazione diretta dell'algoritmo Heron. L'unica stranezza è nel calcolare la media evitando l'overflow dei numeri interi: a = (m + n) / 2 non funziona per i numeri biiiig.

typedef uint64_t Z;
Z q(Z x)
{
   Z n=1,a=x,m=0;
   for(;a-m&&a-n;) n=a,m=x/n,a=m/2+n/2+(m&n&1);
   return a;
}

Bel lavoro per evitare l'overflow - non solo per farlo correttamente, ma avendo cura di pensarci in primo luogo e testarlo. Sicuramente apprezzato.
Todd Lehman,

A proposito, è divertente quanto possa essere costosa la divisione su alcune CPU. Anche se questo algoritmo viene eseguito in circa la metà dei passaggi dell'algoritmo abacus, ha un tempo di esecuzione circa 5 volte più lento dell'algoritmo abacus quando lo confronto sulla mia CPU Core i7, a cui non piace fare divisione. Comunque, ma il runtime non è importante qui - solo dimensioni. :) Così bel lavoro !!!
Todd Lehman,

4

C # 64 62 55

Dato che questo è un (e sono terribile con la matematica), e il runtime è solo un suggerimento, ho seguito l'approccio ingenuo che corre in tempo lineare:

decimal f(ulong a){var i=0m;while(++i*i<=a);return--i;}

( test su dotnetfiddle )

Certo, è terribilmente lento per input più grandi.


1
Potresti riuscire a radere un personaggio cambiando return i-1in return--i?
Todd Lehman,

Nell'espressione i*i<=a, è garantito che sia l'aritmetica intera del solito tipo? (Non ho familiarità con C #.) In tal caso, e se C # consente la conversione di numeri interi impliciti in booleano come fa C, allora potresti essere in grado di salvare un altro carattere modificandolo in a/i/i.
Todd Lehman,

1
@ToddLehman In realtà si tratta di un'aritmetica a virgola fissa ( Decimal, valore massimo e precisione più elevati), per evitare l'overflow poiché il risultato della moltiplicazione potrebbe potenzialmente andare oltre UInt64.MaxValue. Ma C # non ha conversioni implicite in booleano comunque. Dovrei essere in grado di cambiare il returnpensiero, grazie. Lo farò quando torno a un computer.
Bob,

3

Clojure - 51 o 55 byte

Controlla tutti i numeri da n a 0, dando il primo dove x^2 <= n. Il tempo di esecuzione èO(n - sqrt n)

Senza nome:

(fn[x](first(filter #(<=(* % %)x)(range x -1 -1))))

Di nome:

(defn f[x](first(filter #(<=(* % %)x)(range x -1 -1))))

Esempio:

(map (fn[x](first(filter #(<=(* % %)x)(range x -1 -1)))) (range 50))
=> (0 1 1 1 2 2 2 2 2 3 3 3 3 3 3 3 4 4 4 4 4 4 4 4 4 5 5 5 5 5 5 5 5 5 5 5 6 6 6 6 6 6 6 6 6 6 6 6 6 7)

3

Befunge 93 - 48 byte o 38 caratteri

101p&02p>02g01g:*`#v_01g1-.@
        ^  p10+1g10<        

Provalo qui.


1
Ok, è fantastico. Bel lavoro! Ho inserito 17, ho cliccato su Creep e poi su Esegui, e ne è uscito 4! :)
Todd Lehman,

3

Cobra - 62

do(n as uint64)as uint64
    o=n-n
    while o*o<n,o+=1
    return o

Lotto - 74

set a=0
:1
set /ab=%a%*%a%
if %b% LSS %1 set /aa=%a%+1&goto 1
echo %a%


3

J (10)

Molto, molto, molto ispirato dalla risposta di @Dennis :

<.@%~^&1.5

E un po 'più lungo, ma con prestazioni migliori (sospetto):

<.@(-:&.^.)

floor(halve under log)

Per eseguire, vengono inserite le parti rientrate:

   f=:<.@%~^&1.5
   f 0 8 12 16
0 2 3 4
   g=:<.@(-:&.^.)
   g 0 8 12 16
0 2 3 4

Come si esegue questo per un dato intero?
Dennis,

1
@Dennis Vedi risposta
ɐɔıʇǝɥʇuʎs,

3

APL - 12 caratteri, 19 byte

{⌊(⍵*1.5)÷⍵}

esempio usare:

{⌊(⍵*1.5)÷⍵}17

ritorna 4

Test vettoriale

{⌊(⍵*1.5)÷⍵}¨0 1 2 3 4 8 9 15 16 65535 65536 18446744073709551615

ritorna

1 1 1 1 2 2 3 3 4 255 256 4294967296

Prova online

Un grande ringraziamento a : "ssdecontrol" dell'utente per l'algoritmo


1
Benvenuti in PPCG! Normalmente segniamo APL come un byte per carattere. A meno che la sfida non lo specifichi, non è necessario contare in UTF-8. Qualsiasi codifica esistente va bene, e c'è una vecchia tabella di codici APL del passato che utilizza un singolo byte per ogni carattere. Il fatto che APL sia precedente a ASCII è una cattiva ragione per penalizzarlo per l'utilizzo di caratteri non ASCII. ;) (Detto questo, questa sfida piuttosto vecchia sembra segnare comunque dai personaggi.)
Martin Ender,

@MartinEnder Grazie per la calorosa accoglienza e suggerimenti :)
QuantumKarl

1
01! Usando Dyalog APL , puoi impostare ⎕DIV←1(che molti usano come predefinito) per ottenere il risultato corretto.
Adám,

2

C99 (108 caratteri)

Ecco la mia soluzione in C99, che è adattata da un algoritmo in un articolo su Wikipedia . Sono sicuro che deve essere possibile fare molto meglio di questo in altre lingue.

golfed:

uint64_t s(uint64_t n){uint64_t b=1,r=0;while(n/b/4)b*=4;for(;b;b/=4,r/=2)n>=r+b?r+=b,n-=r,r+=b:0;return r;}

Parzialmente golf:

uint64 uint64_sqrt(uint64 n)
{
  uint64 b = 1, r = 0;
  while (b <= n / 4)
    b *= 4;
  for (; b; b /= 4, r /= 2)
    if (n >= r + b)
      { r += b; n -= r; r+= b; }
  return r;
}

Ungolfed:

uint64_t uint64_sqrt(uint64_t const n)
{
  uint64_t a, b, r;

  for (b = 1; ((b << 2) != 0) && ((b << 2) <= n); b <<= 2)
    ;

  a = n;
  r = 0;
  for (; b != 0; b >>= 2)
  {
    if (a >= r + b)
    {
      a -= r + b;
      r = (r >> 1) + b;
    }
    else
    {
      r >>= 1;
    }
  }

  // Validate that r² <= n < (r+1)², being careful to avoid integer overflow,
  // which would occur in the case where n==2⁶⁴-1, r==2³²-1, and could also
  // occur in the event that r is incorrect.
  assert(n>0? r<=n/r : r==0);  // Safe way of saying r*r <= n
  assert(n/(r+1) < (r+1));     // Safe way of saying n < (r+1)*(r+1)

  return r;
}

1
Suggerimento: non è necessario a, utilizzare n.
edc65,

Ah sì. Grazie. Nella mia versione originale, stavo sostenendo in nmodo che appena prima di tornare potessi fare l'affermazione (non mostrata) che r ^ 2 <= n <(r + 1) ^ 2. Con quell'asserzione omessa, è più necessario rimanere nintatti.
Todd Lehman,

@ edc65 - Grazie ancora per averlo sottolineato. Ho aggiornato il mio codice per riflettere ciò, oltre ad aggiungere un paio di altri trucchi per il golf. constAggiunte anche le asserzioni originali e rese n nella versione non rigata.
Todd Lehman,

2

JavaScript 73 81 (per soddisfare i requisiti dei numeri a 64 bit)

n=prompt();g=n/3;do{G=g,g=(n/g+g)/2}while(1E-9<Math.abs(G-g))alert(Math.floor(g))

Implementazione dell'algoritmo Heron of Alexandria ...


Bello! Funziona con tutti gli ingressi interi a 64 bit senza segno?
Todd Lehman,

Prova come potrei, questo sembra funzionare solo fino a 32 bit ... Con mia grande delusione ...
WallyWest,

Sicuramente l'ultimo | 0 tronca qualsiasi valore a 32 bit. Usi Math.floor invece?
edc65,

@ edc65 In realtà hai ragione, sembra colpire |0fino a 32 bit mentre Math.floorè più efficace a 64 bit ... Ho aggiornato il mio codice, dovendo prendere altri 8 caratteri per farlo ...
WallyWest

@ edc65 Ho appena pensato ... avrebbe funzionato ~~ x a 64 bit?
WallyWest,

2

Powershell (52) Limitato a Int32 (da -2.147.483.648 a 2.147.483.647)

function f($n){($n/2)..0|%{if($_*$_-le$n){$_;exit}}}

Sto urlando a Powershell in questo momento cercando di far funzionare l'ultimo caso di test, ma qualunque cosa faccia Powershell finisce usando la variabile pipeline $ _ come Int32, e non riesco a trovare un modo per aggirarlo in questo momento.

Quindi limiterò la mia risposta per ora. Se riesco a trovare un modo migliore per gestire uint64s, lo modificherò. (L'ultimo caso di test è troppo grande per il normale tipo Int64 di Powershell, comunque!)

Ecco alcuni casi di test (con un po 'di output extra che ho usato per tenere traccia del tempo)

f 17
4
Elapsed Time: 0.0060006 seconds

f 65
8
Elapsed Time: 0.0050005 seconds

f 65540
256
Elapsed Time: 1.7931793 seconds

f 256554
506
Elapsed Time: 14.7395391 seconds

Non conosco i miei O (), ma questo sembra un salto piuttosto drammatico.


2

Avvertenza: a partire dal 2011, R non aveva alcun supporto integrato per numeri interi a 64 bit come avevo immaginato. Queste risposte potrebbero non essere valide su questo tecnicismo, ma poi di nuovo R è cambiata molto negli ultimi 3 anni.


R, 85

Utilizzando il metodo di Newton:

function(n){s=F
x=n
y=(1/2)*(x+n/x)
while(abs(x-y)>=1){x=y
y=(1/2)*(x+n/x)}
trunc(y)}

che converge quadraticamente. +2 caratteri per assegnare la funzione a una variabile per il benchmarking:

microbenchmark(q(113424534523616))
# Unit: microseconds
#                expr    min      lq median      uq    max neval
#  q(113424534523616) 24.489 25.9935 28.162 29.5755 46.192   100

R, 37

Forza bruta:

function(n){t=0
while(t^2<n) t=t+1
t}

E lo stesso controllo:

microbenchmark::microbenchmark(q(113424534523616),times=1)
# Unit: seconds
#                 expr      min       lq   median       uq      max neval
#   q(113424534523616) 4.578494 4.578494 4.578494 4.578494 4.578494     1

R, 30

Il trucco esponenziale economico / brillante :

function(n) trunc(n^(1.5)/n)

che è anche molto veloce (anche se non veloce come quello incorporato):

microbenchmark(q(113424534523616),sqrt(113424534523616))
# Unit: nanoseconds
#                   expr min    lq median    uq  max neval
#     z(113424534523616) 468 622.5  676.5 714.5 4067   100
#  sqrt(113424534523616)  93 101.0  119.0 160.5 2863   100

2

C, 38

f(n){int m;while(++m*m<=n);return--m;}

Traduzione della mia proposta Forth. Lento ma corretto. O (√ n). Testato su OS X (64 bit).


2

dc, 50 byte

dc -e"?dsist[lt2/dstd*li<B]dsBx[lt1+dstd*li!<A]dsAxlt1-f"

Distanziati e spiegati:

               # The idea here is to start with the input and reduce it quickly until it is
               # less than what we want, then increment it until it's just right
?              # Take input from stdin
d si st        # Duplicate input, store in `i' and in `t'
[              # Begin macro definition (when I write in dc, "macro"=="function")
 lt            # Load t, our test term
 2/            # Divide t by two
 d st          # Store a copy of this new term in `t'
 d*            # Duplicate and multiply (square)
 li<B          # Load i; if i<(t^2), execute B
] d sB x       # Duplicate, store function as `B', and execute
               # Loop ends when t^2 is less than i
[              # Begin macro definition
 lt            # Load t, our test term
 1+            # Increment
 d st          # Store a copy of this new term in `t'
 d*            # Duplicate and multiply (square)
 li!<A         # Load i; if i>=(t^2), execute A
] d sA x       # Duplicate, store function as `A', and execute
               # Loop ends when t^2 == i+1
lt 1- f        # Load t, decrement, and dump stack

Sembra che l'ultimo caso di test si blocchi. Proverò a ripararlo.
Joe,

Risolto. Ora accetta input molto grandi; per fortuna, la correzione mi ha permesso di rimuovere un po 'di brutto codice all'inizio.
Joe,

2

C, 139 137 136 byte

Il mio primo tentativo di code golf. Sembra che sia il più corto in C che si adatta al requisito "efficiente", poiché corre nel O(log n)tempo, usando solo addizioni e bit shift. Anche se sono sicuro che potrebbe essere ancora più breve ...

Dovrebbe funzionare bene anche per valori interi più grandi, purché la a=32parte venga modificata a=NUMBITS/2.

typedef uint64_t x;x f(x o){x a=32,t=0,r=0,y=0,z;for(;a--+1;){z=(x)3<<2*a;y*=2;t++<r?y++,r-=t++:t--;t*=2;r*=4;r+=(o&z)>>2*a;}return y;}

Bel lavoro! Non l'ho eseguito per testare, ma il codice sembra interessante. C'è una ragione per cui hai scritto (t++)invece che solo t++nel compito a r?
Todd Lehman,

1
@ToddLehman No, mi sono appena perso. Bella presa!
Chris,

A proposito, adoro il a--+1modo di evitare di scrivere a-- != UINT64_C(-1). Hai imparato quel trucco da qualche parte o lo hai inventato tu stesso?
Todd Lehman,

1
@ToddLehman Grazie! L'ho capito da solo.
Chris,

1

C - 50 (61 senza globale)

typedef uint64_t T;T n,i;f(){while(++i*i<=n);--i;}

Utilizza le variabili globali come parametro e restituisce valore per risparmiare spazio.

Nessuna versione globale:

typedef uint64_t T;T f(T n){T i=0;while(++i*i<=n);return--i;}

1
Non penso che usare le variabili globali sia legale. Almeno dì quanto tempo sarebbe legittimamente e fornisci una versione legittima
orgoglioso haskeller il

@proud haskeller Perché le variabili globali dovrebbero essere vietate?
mantale,

@mantal perché è necessario fornire un programma / metodo eseguibile.
Marciano,

@ Marciano.Andrade il codice fornito è eseguibile.
mantale,

1

C ++ 125

int main()
{
uint64_t y;cin>>y;
double x=y/2,d,z;
while((d=(x*x-y))>0.5)
{
d<0?x+=0.5:x-=0.5;
}
cout<<(uint64_t)x;
}

Bello! Che ne dici di x+=(d<0)-0.5;... salva altri 5 personaggi?
Todd Lehman,

A proposito, questo non è (ma dovrebbe essere) nella forma di una funzione, come menzionato nella dichiarazione del problema. (Va bene, tecnicamente, sì, mainè una funzione, ma non è richiamabile dall'interno di un programma come f(y)sarebbe.)
Todd Lehman,

Penso che tu possa omettere la coppia più interna di parentesi e scrivere while((d=x*x-y)>0.5)invece di while((d=(x*x-y))>0.5). Salva altri 2 personaggi. :)
Todd Lehman,

Ogni 0,5 può essere modificato in 0,5
Yytsi
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.