Problema:
Na sua escolha de idioma, escreva a função mais curta que retorna o piso da raiz quadrada de um número inteiro de 64 bits não assinado.
Casos de teste:
Sua função deve funcionar corretamente para todas as entradas, mas aqui estão algumas que ajudam a ilustrar a idéia:
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
Regras:
- Você pode nomear sua função como quiser. (As funções sem nome, anônima ou lambda são boas, desde que sejam de alguma forma chamadas.)
- A contagem de caracteres é o que mais importa nesse desafio, mas o tempo de execução também é importante. Tenho certeza de que você poderia procurar iterativamente para cima a resposta em tempo O (√n) com uma contagem de caracteres muito pequena, mas o tempo O (log (n)) seria realmente melhor (ou seja, assumindo um valor de entrada n, não um comprimento de bit de n).
- Você provavelmente desejará implementar a função usando puramente inteiro e / ou aritmética booleana. No entanto, se você realmente deseja usar cálculos de ponto flutuante, tudo bem, desde que você não chame nenhuma função de biblioteca. Portanto, simplesmente dizer
return (n>0)?(uint32_t)sqrtl(n):-1;
em C está fora dos limites, mesmo que produza o resultado correto. Se você estiver usando aritmética de ponto flutuante, você pode usar*
,/
,+
,-
, e exponenciação (por exemplo,**
ou^
se é um built-in operador no idioma de sua escolha, mas a exponenciação única de poderes não inferior a 1 ). Essa restrição é para evitar "trapaça" chamandosqrt()
ou uma variante ou aumentando um valor para a ½ potência. - Se você estiver usando operações de ponto flutuante (consulte # 3), não será necessário que o tipo de retorno seja inteiro; apenas que o valor de retorno seja um número inteiro, por exemplo, floor (sqrt (n)), e seja capaz de manter qualquer valor de 32 bits não assinado.
- Se você estiver usando C / C ++, poderá assumir a existência de tipos inteiros de 64 e 32 bits não assinados, por exemplo,
uint64_t
euint32_t
conforme definido emstdint.h
. Caso contrário, verifique se o tipo inteiro é capaz de conter qualquer número inteiro não assinado de 64 bits. - Se o seu idioma não suportar números inteiros de 64 bits (por exemplo, o Brainfuck aparentemente possui apenas o número inteiro de 8 bits), faça o seu melhor com isso e indique a limitação no título da resposta. Dito isso, se você puder descobrir como codificar um número inteiro de 64 bits e obter corretamente a raiz quadrada usando aritmética primitiva de 8 bits, terá mais poder para você!
- Divirta-se e seja criativo!
code-golf
math
arithmetic
Todd Lehman
fonte
fonte
O(log_2 n) === O(log_4 n)
.log_4(n) = log_2(n) / log_2(2) = log_2(n) / 2
Respostas:
CJam, 17 (ou 10) bytes
Experimente online verificando os casos de teste:
Ele não passará no último caso de teste devido a problemas de arredondamento, mas como
18446744073709551615
não é um número inteiro no CJam (é um número inteiro grande ), ainda somos bons, certo?Caso contrário, o código a seguir (e um pouco mais longo) corrigirá esses erros:
Não é mais a solução mais curta, mas é uma faaast .
Como funciona
fonte
<.@%~^&1.5
. Posso postar isso como uma resposta separada (já que é basicamente uma porta exata sua)?4294967295
e4294967296
olhar muito semelhante ...Haskell,
2826Acredito que esta é a entrada mais curta de qualquer idioma que não foi projetado para jogar golfe.
Nomeia uma função
s
com parâmetroa
e retorna um menos o primeiro número cujo quadrado é maior quea
. Corre incrivelmente devagar (O (sqrt n), talvez?).fonte
[...]!!0
) não seria menor que o cabeçalho?Golfscript, 17 caracteres
Eu poderia nomear minha função da maneira que quisesse, mas decidi não nomeá-la. Adicione dois caracteres para nomear, adicione três para nomear e não deixe na pilha; subtraia um caractere se o fornecimento de um programa completo estiver OK.
Essa abominação não é executada no tempo logarítmico no valor da entrada, e não no tempo O (sqrt n), leva uma quantidade linear de tempo para produzir o resultado. Também ocupa muito espaço. Absolutamente horrendo. Mas ... isso é código-golfe.
O algoritmo é:
fonte
Pitão , 14 caracteres
Fornece uma função nomeada, s, que calcula a raiz quadrada filtrando a lista de 0 a n para o quadrado ser maior que a entrada e, em seguida, imprime o último número desse tipo. Não usa exponenciação ou flutua.
Exemplo de uso:
fonte
Retina (não concorrente - O idioma é mais novo que o desafio), 43
Enquanto trabalhava nessa resposta , ocorreu-me que um método semelhante pode ser usado para calcular raízes quadradas inteiras usando retina:
Isso se baseia no fato de que quadrados perfeitos podem ser expressos como
1+3+5+7+...
e pelo corolário que o número de termos nessa expressão é a raiz quadrada.Experimente online. (Primeira linha adicionada para permitir a execução de vários casos de teste.)
Obviamente, devido à conversão decimal em unária, isso funcionará apenas para entradas relativamente pequenas.
fonte
Perl, 133 caracteres
Não é o menor de longe, mas usa um algoritmo dígito por dígito para lidar com qualquer entrada de tamanho e é executado no tempo O (log n). Converte livremente entre números como seqüências de caracteres e números como números. Como o maior produto possível é a raiz até agora com o quadrado de um único dígito, ele deve conseguir a raiz quadrada de até 120 ou mais números em um sistema de 64 bits.
Descomprimido, ou seja:
fonte
if length%2
vez deif(length)%2
? Isso reduziria 1 caractere. Além disso, seria bom dizer em$y=$z,$d=$_ if
vez de($y,$d)=($z,$_)if
? Eu acho que isso cortaria mais 3 personagens.for
loop da seguinte forma:$a<($z=$_*(20*$r+$_))or$y=$z,$d=$_ for(1..9);
%2
), mas as outras são válidas. Vou trabalhar com eles.for
não precisa de parênteses; adicionando isso às suas sugestões, me dá 6 caracteres no total. Obrigado!Matlab (56) / Oitava (55)
Ele elabora a raiz quadrada usando um método de ponto fixo. Ele converge no máximo 36 etapas (para 2 ^ 64-1 como argumento) e depois verifica se é a mais baixa das raízes inteiras 'possíveis'. Como sempre usa 36 iterações, possui um tempo de execução de O (1) = P
O argumento é assumido como uint64.
Matlab:
Oitava:
fonte
Ruby - 36 caracteres
fonte
while
loop termina exatamente quando g converge para o piso (√n), que é o valor desejado. Você vê algum caso em que isso não seria verdade?Python (39)
A abordagem recursiva natural. Conta as raízes quadradas em potencial até o quadrado ficar muito alto e diminui em 1. Use o Stackless Python se você estiver preocupado em exceder a profundidade da pilha.
O
and/or
idioma é equivalente ao operador ternário comoEdit: eu posso em vez de obter 25 caracteres , explorando a regra ", você pode usar
*
,/
,+
,-
, e exponenciação (por exemplo,**
ou^
se é uma exponenciação built-in operador no idioma de sua escolha, mas apenas de poderes não inferior a 1). " (Editar: Aparentemente, Dennis já encontrou e explorou esse truque.)Eu uso o operador
//
de divisão inteira do Python 3 para arredondar para baixo. Infelizmente, gasto muitos caracteres para que o cason=0
não dê uma divisão por 0 erro. Se não fosse por isso, eu poderia fazer 18 caracteresAs regras também não diziam que a função tinha que ser nomeada (dependendo de como você interpreta "Você pode nomear sua função como quiser"), mas, se o fizer, serão mais dois caracteres.
fonte
C99 (58 caracteres)
Este é um exemplo de resposta que eu não consideraria uma boa, embora seja interessante para mim do ponto de vista do código de golfe, porque é muito perversa, e eu apenas pensei que seria divertido jogar na mistura:
Original: 64 caracteres
A razão pela qual este é terrível é que ele é executado no tempo O (√n) em vez do tempo O (log (n)). (Onde n é o valor de entrada.)
Editar: 63 caracteres
Alterando o
r-1
para--r
e confinando-o parareturn
:Editar: 62 caracteres
Movendo o incremento do loop para dentro da parte condicional do loop (nota: isso tem um comportamento não garantido, porque a ordem das operações com relação ao operador de pré-incremento é específica do compilador):
Editar: 60 caracteres
Adicionando a
typedef
para ocultaruint64_t
(crédito ao usuário technosaurus por esta sugestão).Editar: 58 caracteres
Agora exigindo que o segundo parâmetro seja passado como 0 na invocação da função, por exemplo, em
r(n,0)
vez de apenasr(n)
. Ok, para a minha vida, neste momento não consigo ver como comprimir isso mais ... alguém?fonte
uint64_t s(uint64_t n){for(uint64_t r=n;--n>r/n;);return n;}
.--n
quandon==0
seria –1 e esses são valores não assinados, então –1 seria 2⁶⁴ – 1.#define Z uint64_t
... ou typedef irá salvar um casaln/++r/r
tem um comportamento indefinido ....Golfscript - 14 caracteres
Encontre o menor número
i
menor que a entradan
para a qualn < i*i
. Retornoi - 1
.Ou seja,
[0..n-1].first(i => n < i*i) - 1
Explicação para aqueles que também não conhecem o Golfscript, para exemplo de chamada com entrada
5
:fonte
1
provavelmente leva dois caracteres.Haskell,
147138134128 bytesNão é o código mais curto do mundo, mas é executado em O (log n) e em números de tamanho arbitrário:
Isso faz uma pesquisa binária do intervalo [0..n] para encontrar a melhor aproximação mais baixa ao sqrt (n). Aqui está uma versão não destruída:
Editar: salvou dois bytes substituindo as cláusulas "caso contrário" por "0 <1" como uma versão mais curta de "True" e mais algumas inserindo g * g.
Além disso, se você está feliz com O (sqrt (n)), você pode simplesmente fazer
para 35 caracteres, mas que graça é essa?
Edit 2: Acabei de perceber que, uma vez que os pares são classificados por ordem do dicionário, em vez de fazer min2Cycle. mapear fst, eu posso apenas fazer fst. min2Cycle. No código golfed, isso significa substituir f $ map fst por fst $ f, economizando mais 4 bytes.
Editar 3: economizou mais seis bytes graças ao proudhaskeller!
fonte
JavaScript
918886: Otimizado para velocidadeJavaScript 46: não otimizado para velocidade
Aqui está um JSFiddle: http://jsfiddle.net/rmadhuram/1Lnjuo4k/
fonte
function s(n){for(a=1;++a*a<n;);return a}
C 95
97Editar Typedef, sugerido por @Michaelangelo
Isso deve ser mais ou menos uma implementação direta do algoritmo Heron. O único problema é calcular a média evitando o excesso de números inteiros: a = (m + n) / 2 não funciona para números biiiig.
fonte
C #
646255Como esse é um código-golfe (e eu sou péssimo em matemática), e o tempo de execução é apenas uma sugestão, eu fiz a abordagem ingênua que é executada em tempo linear:
( teste no dotnetfiddle )
Obviamente, é terrivelmente lento para entradas maiores.
fonte
return i-1
parareturn--i
?i*i<=a
, isso é garantido como aritmética inteira do tipo usual? (Eu não estou familiarizado com C #.) Nesse caso, e se o C # permitir a conversão de números implícitos em booleano como C, então você poderá salvar mais um caractere alterando-o paraa/i/i
.Decimal
maior valor máximo e precisão), para evitar o estouro, pois o resultado da multiplicação pode potencialmente ir alémUInt64.MaxValue
. Mas o C # não tem conversões implícitas em booleano. Eu deveria ser capaz de mudar issoreturn
, obrigado. Farei isso quando voltar ao computador.Clojure - 51 ou 55 bytes
Verifica todos os números de n a 0, dando o primeiro onde
x^2 <= n
. O tempo de execução éO(n - sqrt n)
Sem nome:
Nomeado:
Exemplo:
fonte
Befunge 93 - 48 bytes ou 38 caracteres
Experimente aqui.
fonte
Cobra - 62
Lote - 74
fonte
Haskell,
535049 caracteres, O (log n)esta solução implementa o método newton-raphson, embora ele procure números inteiros em vez de números flutuantes. wiki: http://en.wikipedia.org/wiki/Newton%27s_method
a complexidade parece ser sobre O (log n), mas há uma prova disso? por favor responda nos comentários.
fonte
\g->div(n+g^2)$2*g
salva 7 bytes.J (10)
Muito, muito, muito inspirado pela resposta de @Dennis :
E um pouco mais, mas com melhor desempenho (suspeito):
floor(halve under log)
Para executar, são inseridas peças recuadas:
fonte
APL - 12 caracteres, 19 bytes
exemplo de uso:
retorna 4
Vetor de teste
retorna
1 1 1 1 2 2 3 3 4 255 256 4294967296
Experimente on-line
Muito obrigado a : usuário "ssdecontrol" do algoritmo
fonte
0
→1
! Usando o Dyalog APL , você pode definir⎕DIV←1
(que muitos usam como padrão) para obter o resultado correto.C99 (108 caracteres)
Aqui está minha própria solução no C99, que é adaptada de um algoritmo em um artigo na Wikipedia . Tenho certeza de que deve ser possível fazer muito melhor que isso em outros idiomas.
Golfe:
Parcialmente jogado:
Ungolfed:
fonte
a
, usen
.n
para que, pouco antes de retornar, pudesse fazer a afirmação (não mostrada) de que r ^ 2 <= n <(r + 1) ^ 2. Com essa afirmação omitida, é mais necessário manter-sen
intacto.const
em n na versão ungolfed.JavaScript
7381 (para atender aos requisitos de números de 64 bits)n=prompt();g=n/3;do{G=g,g=(n/g+g)/2}while(1E-9<Math.abs(G-g))alert(Math.floor(g))
Implementando o algoritmo de Heron de Alexandria ...
fonte
|0
afetar até 32 bits, enquantoMath.floor
é mais eficaz em 64 bits ... Atualizei meu código, tendo que extrair 8 caracteres extras para fazer isso ...Powershell (52) Limitado ao Int32 (-2.147.483.648 a 2.147.483.647)
Estou gritando com o Powershell agora, tentando fazer com que o último caso de teste funcione, mas não importa o que eu faça, o Powershell acaba usando a variável de pipeline $ _ como um Int32, e não consigo encontrar uma maneira de contornar isso agora.
Então, vou limitar minha resposta por enquanto. Se eu conseguir encontrar uma maneira melhor de lidar com o uint64s, editarei. (O último caso de teste é muito grande para o tipo Int64 normal do Powershell, a propósito!)
Aqui estão alguns casos de teste (com um pouco de saída extra que eu costumava acompanhar o tempo)
Não conheço meus O (), mas isso parece um salto bastante dramático.
fonte
Advertência: a partir de 2011, o R não tinha suporte interno para números inteiros de 64 bits, como eu supunha. Essas respostas podem ser inválidas nesse aspecto técnico, mas, novamente, o R mudou muito nos últimos 3 anos.
R, 85
Usando o método de Newton:
que converge quadraticamente. +2 caracteres para atribuir a função a uma variável para benchmarking:
R, 37
Força bruta:
E a mesma verificação:
R, 30
O truque barato / brilhante de exponenciação :
que também é muito rápido (embora não tão rápido quanto o interno):
fonte
C, 38
Tradução da minha quarta submissão. Lento, mas correto. O (√n). Testado no OS X (64 bits).
fonte
dc, 50 bytes
Espaçados e explicados:
fonte
C,
139137136 bytesMinha primeira tentativa no código de golfe. Parece que é o menor em C que se encaixa no requisito "eficiente", pois é executado no
O(log n)
tempo, usando apenas mudanças de adição e de bits. Embora eu tenha certeza que poderia ser mais curto ainda ...Deve funcionar muito bem para valores inteiros maiores também, desde que a
a=32
peça seja alterada paraa=NUMBITS/2
.fonte
(t++)
não apenast++
na tarefar
?a--+1
como uma forma de escrita evitara-- != UINT64_C(-1)
. Você aprendeu esse truque em algum lugar ou inventou você mesmo?C - 50 (61 sem global)
Ele usa variáveis globais como parâmetro e retorna valor para economizar espaço.
Nenhuma versão global:
fonte
C ++ 125
fonte
x+=(d<0)-0.5;
... salva mais 5 caracteres?main
é uma função, mas não é exigível a partir de dentro de um programa como umf(y)
seria.)while((d=x*x-y)>0.5)
vez dewhile((d=(x*x-y))>0.5)
. Salva mais 2 caracteres. :)