정수의 정수 제곱근 [닫힘]


12

문제:

선택한 언어에서 부호없는 64 비트 정수의 제곱근의 바닥을 반환하는 가장 짧은 함수를 작성하십시오.

테스트 사례 :

함수는 모든 입력에 대해 올바르게 작동해야하지만 아이디어를 설명하는 데 도움이되는 몇 가지가 있습니다.

               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

규칙 :

  1. 원하는대로 함수 이름을 지정할 수 있습니다. 이름이 없거나 익명이거나 람다 함수는 어떤 식 으로든 호출 할 수있는 한 괜찮습니다.
  2. 문자 수는이 문제에서 가장 중요한 요소이지만 런타임도 중요합니다. 매우 작은 문자 수로 O (√n) 시간에 대한 답변을 반복적으로 위쪽으로 스캔 할 수 있다고 확신하지만 O (log (n)) 시간은 실제로 더 좋을 것입니다 (즉, 입력 값 n을 가정하면, n의 비트 길이가 아님).
  3. 순수한 정수 및 / 또는 부울 artithmetic을 사용하여 함수를 구현하고 싶을 것입니다. 그러나 실제로 부동 소수점 계산을 사용하려면 라이브러리 함수를 호출하지 않는 한 괜찮습니다. 따라서 return (n>0)?(uint32_t)sqrtl(n):-1;C에서 말하는 것은 올바른 결과를 얻을지라도 한계를 벗어납니다. 당신 부동 소수점 연산을 사용하고, 당신이 사용할 수있는 경우 *, /, +, -, 및 지수 (예, **또는 ^그것은 선택의 여지가 귀하의 언어로 운영자 내장,하지만 만약 힘의 지수는 이하 1 이상 ). 이 제한은 전화 sqrt()또는 변형 을 호출 하거나 값을 ½ 제곱으로 "속임수"를 방지 하는 것입니다.
  4. 부동 소수점 연산을 사용하는 경우 (# 3 참조) 반환 유형이 정수일 필요는 없습니다. 반환 값이 정수 (예 : floor (sqrt (n)))이고 부호없는 32 비트 값을 보유 할 수 있다는 것만 해당합니다.
  5. C / C ++를 사용하는 경우 부호없는 64 비트 및 32 비트 정수 유형이 있다고 가정 할 수 있습니다 (예 : uint64_t및 uint32_t에 정의 됨) stdint.h. 그렇지 않으면 정수 유형이 부호없는 64 비트 정수를 보유 할 수 있는지 확인하십시오.
  6. 언어가 64 비트 정수를 지원하지 않는 경우 (예 : Brainfuck은 8 비트 정수만 지원함)이를 최대한 활용하여 답변 제목에 제한을 기술하십시오. 즉, 64 비트 정수를 인코딩하고 8 비트 프리미티브 산술을 사용하여 제곱근을 올바르게 얻는 방법을 알아낼 수 있다면 더 많은 힘을 얻을 수 있습니다!
  7. 즐기고 창의력을 발휘하십시오!

7
"하지만 O (log₄ (n)) 시간이 실제로 더 나을 것입니다." -얼마나 좋아? 보너스가 있습니까? 어려운 요구입니까? 본질적으로 별도의 도전입니까? 실제로 점수에 영향을 미치지 않는 좋은 아이디어입니까?
— John Dvorak

3
일반적으로 알고리즘 복잡성을 도출하기 위해 입력 값 대신 입력 크기 를 사용합니다 . 그런 의미에서 증가 및 재시도 알고리즘은 속도가 기하 급수적으로 증가합니다.
— John Dvorak

3
음 ... O(log_2 n) === O(log_4 n). log_4(n) = log_2(n) / log_2(2) = log_2(n) / 2
— John Dvorak

1
2/4는 계산됩니까?
— Milo

1
대부분의 부동 소수점 데이터 형식에는이 작업에 필요한 정밀도가 없습니다. 전체 입력 범위에 대해 53 개의 유효 비트로는 충분하지 않습니다.
— user2357112는 Monica

답변:


14

CJam, 17 (또는 10) 바이트

{_1.5#\/i}

테스트 사례를 확인하여 온라인 으로 사용해보십시오 .

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

반올림 문제로 인해 마지막 테스트 사례를 통과하지는 못하지만 CJam 18446744073709551615의 정수 ( 큰 정수 ) 가 아니기 때문에 여전히 훌륭합니다.

그렇지 않은 경우 다음 (그리고 약간 더 긴) 코드가 이러한 오류를 수정합니다.

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

더 이상 가장 짧은 해결책은 아니지만 faaast .

작동 원리

__    " 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. ";

하하하! 죄송합니다. 기술적 인 문제가 있습니다. 분 수력은 없다고 말 했어야 했어요. 그러나 귀하의 코드는 실제로 명시된 규칙을 준수하므로이를 찬성합니다. :)
— Todd Lehman

2
CJam은 전체 입력 범위를 다루기 위해 임의의 정밀도 소수를 가지고 있습니까?
— isaacg

또한 int로 캐스트 할 때 NaN-> 0을 사용하는 좋은 해킹.
— isaacg

깔끔한 아이디어는 J와 정확히 동일한 문자 수로 표현할 수 있습니다 <.@%~^&1.5. 기본적으로 정확한 포트이므로 이것을 별도의 답변으로 게시 할 수 있습니까?
— ɐɔıʇǝɥʇuʎs

@ ɐɔıʇǝɥʇuʎs : 계속하십시오. 그러나 방금 마지막 테스트 사례를 포함하여 많은 수의 솔루션이 잘못 반올림 될 수 있음을 알았습니다. 내 방어에서, 그것은 단지 때문에 내 검사를 통과 4294967295하고 4294967296보면 매우 ... 유사
— 데니스

10

하스켈, 28 26

골프 용으로 설계되지 않은 언어 중에서 가장 짧은 항목이라고 생각합니다.

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

s매개 변수를 사용하여 함수의 이름을 지정하고 a제곱이보다 큰 첫 번째 숫자에서 1을 뺀 값을 반환합니다 a. 엄청나게 느리게 실행됩니다 (O (sqrt n), 아마도?).


1
리스트 인덱스 ( [...]!!0)가 헤드보다 짧지 않습니까?
— isaacg

@isaacg 그렇습니다. 감사합니다 :-)
— Zaq

7

골프 스크립트, 17 자

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

원하는 방식으로 함수 이름을 지정할 수 있지만 이름을 전혀 지정하지 않기로 결정했습니다. 이름을 지정하려면 두 문자를 추가하고 이름을 지정하려면 세 문자를 추가하고 스택에 두지 말고 전체 프로그램을 제공해도 문제가 없으면 한 문자를 빼십시오.

이 가증은 O (sqrt n) 시간이 아닌 입력 값에서 로그 시간이 아니라 결과를 생성하는 데 엄청난 선형 시간이 걸립니다. 또한 많은 공간이 필요합니다. 물론 끔찍합니다. 그러나 ... 이것은 코드 골프입니다.

알고리즘은 다음과 같습니다.

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

나는 그것을 좋아한다 !! 잘 하셨어요! 그것은 아름답다.
— Todd Lehman

7

Pyth , 14 자

DsbR;fgb*TTL'b

입력 값보다 큰 제곱에 대해 0에서 n까지의 목록을 필터링하여 제곱근을 계산 한 다음 마지막 숫자를 인쇄하는 명명 된 함수 s를 제공합니다. 지수 나 부동 소수점을 사용하지 않습니다.

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

사용법 예 :

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

레티 나 (비경쟁-언어가 도전보다 새로운 것), 43

이 답변을 수행 하는 동안 비슷한 방법을 사용하여 망막을 사용하여 정수 제곱근을 계산할 수 있습니다.

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

1+

이것은 완전 제곱이로 표현 될 수 있다는 사실에 의존하며 1+3+5+7+...,이 표현에서 항의 수는 제곱근이라는 결론에 의해 결정됩니다.

온라인으로 사용해보십시오. (여러 테스트 케이스를 실행할 수 있도록 첫 번째 행이 추가되었습니다.)

분명히 십진수에서 단항으로의 변환으로 인해 이것은 비교적 작은 입력에 대해서만 작동합니다.


4
(언어는 도전보다 최신 버전)
— mbomb007

@ mbomb007 충분합니다-헤드 라인이 편집되었습니다. 이 답변은 "수행 할 수 있기 때문에"범주에 속하며, 의미있는 방식으로 도전에 참여하기위한 것이 아닙니다.
— 디지털 외상


6

펄, 133 자

가장 짧지는 않지만 숫자 단위 알고리즘을 사용하여 모든 크기 입력을 처리하고 O (log n) 시간으로 실행됩니다. 문자열과 숫자를 자유롭게 변환합니다. 가능한 최대 제품은 한 자리 수의 제곱을 가진 근소이므로 64 비트 시스템에서 최대 120 비트 정도의 제곱근을 사용할 수 있어야합니다.

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}

압축 해제 :

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;
}

좋은! 누군가 Perl 답변을 게시 할 때 궁금합니다. BTW, if length%2대신에 말하는가 if(length)%2? 그것은 1 문자를 깎을 것입니다. 또한 $y=$z,$d=$_ if대신 말하는 것이 효과가 ($y,$d)=($z,$_)if있습니까? 나는 그것이 3 문자를 더 깎을 것이라고 생각합니다.
— Todd Lehman

그리고 이것은 약간 왜곡되고 있지만, 다음 for과 같이 루프를 다시 작성하여 1을 더 줄일 수 있다고 생각합니다 .$a<($z=$_*(20*$r+$_))or$y=$z,$d=$_ for(1..9);
— Todd Lehman

첫 번째 제안은 작동하지 않지만 (라는 이름의 해시 길이를 사용하려고 시도 %2하지만) 다른 제안 은 유효합니다. 나는 그들을 일 것입니다.
— 홉스

1
@ToddLehman 접미사 for는 괄호가 필요하지 않습니다. 당신의 제안에 그것을 추가하면 총 6 문자가 나옵니다. 감사!
— hobbs

5

MATLAB (56) / 옥타브 (55)

고정 소수점 방법을 사용하여 제곱근을 계산합니다. 최대 36 단계로 인수 (2 ^ 64-1의 경우 인수)로 수렴 한 다음 '가능한'정수 근 중 가장 낮은 단계인지 확인합니다. 항상 36 개의 반복을 사용하므로 런타임은 O (1) = P입니다.

인수는 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

옥타브:

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

이것은 나에게 새로운 방법이며, 매우 시원합니다. +1
— seequ

1
기본적으로 en.wikipedia.org/wiki/… 는 약 3700 년으로 추정되는 가장 초기의 알려진 수치 방법 중 하나입니다. 그것은에 의해 정당화 될 수 en.wikipedia.org/wiki/Banach_fixed-point_theorem 놀라 울 정도로 쉽게 증거를 가지고, 그것은) 정말 좋은 =있어
— flawr

5

루비 — 36 자

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

잘 했어요! 최악의 실행 시간은 얼마입니까?
— Todd Lehman

g * g <n이고 응답이 여전히 원하는 값에 근접하지 않은 경우는 어떻습니까? 스크립트가 멈추지 않습니까?
— WallyWest

1
@ToddLehman 솔직히 모르겠습니다. :-/ 이것은 바빌로니아 방식 입니다. 다음은 평균 복잡성에 대한 좋은 증거로 보입니다 . 숫자 자체의 초기 추측은 꽤 나쁘지만, 나는 최악의 경우를 이해하기 위해 앉아서 그 증거를 정말로 알아야합니다. 좀 더 자유 시간이되면 갈 것입니다. :-)
— OI

@WallyWest 내 이해는 whileg가 원하는 값 인 바닥 (√n)으로 수렴 할 때 루프가 정확하게 종료 된다는 것입니다 . 이것이 사실이 아닌 경우가 있습니까?
— OI

4

파이썬 (39)

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

자연 재귀 접근. 제곱이 너무 높아질 때까지 잠재적 제곱근을 세고 1만큼 줄입니다. 스택 깊이를 초과 할까 걱정되면 Stackless Python을 사용하십시오 .

and/or관용구 원계 연산자로 동등

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

편집 : 내가 대신 얻을 수있는 25 개 문자를 규칙 "당신이 사용할 수 있습니다 이용하여 *, /, +, -, 및 지수 (예를, **또는 ^그 권한의 선택의 언어에서 연산자를 내장,하지만 지수가 이하 1 이상 인 경우). " (편집 : Dennis는 이미이 트릭을 찾아서 악용했습니다.)

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

//파이썬 3 의 정수 나누기 연산자 를 사용하여 반올림합니다. 불행히도 n=00으로 나누기 오류가 발생하지 않도록 많은 문자를 사용합니다 . 그렇지 않다면, 나는 18 문자를 할 수 있습니다

lambda n:n**1.5//n 

규칙은 또한 함수의 이름을 지정해야한다고 말하지 않았지만 ( "당신이 원하는대로 함수의 이름을 지정할 수 있습니다."에 따라) 두 문자가 더 있습니다.


— 고마워, 나는 그것을 명확히 할 것이다. 기능 일뿐입니다. 이름을 지정할 필요는 없습니다. 람다 함수는 괜찮습니다. 내가 생각한다면 처음부터 이것을 언급했을 것입니다. 질문을 게시 할 때 C 측면에서 너무 많이 생각하고있었습니다.
— Todd Lehman

4

C99 (58 자)

이것은 좋은 것으로 생각하지 않는 대답의 예입니다. 왜냐하면 코드 골프 관점에서 볼 때 흥미롭지 만 흥미롭지 만 믹스에 던지는 것이 재미있을 것이라고 생각했습니다.

원본 : 64 자

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

이것이 끔찍한 이유는 O (log (n)) 시간이 아니라 O (√n) 시간에 실행되기 때문입니다. (여기서 n은 입력 값입니다.)

편집 : 63 자

변경 r-1에 --r와에 인접 return:

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

편집 : 62 자

루프 증분을 루프의 조건부 내부로 이동 (주의 : 사전 증분 연산자와 관련된 작업 순서는 컴파일러마다 다르기 때문에 이는 보증되지 않은 동작입니다) :

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

편집 : 60 자

typedef숨기기 추가 uint64_t( 이 제안 을 위해 사용자 technosaurus에 대한 신용 )

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

편집 : 58 자

이제 함수를 호출 할 때 예를 들어 r(n,0)just 대신 두 번째 매개 변수가 0으로 전달되어야 r(n)합니다. 좋아, 내 인생 에서이 시점에서 나는 이것을 더 이상 압축하는 법을 볼 수 없다.

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

C ++로 기꺼이 부르고 증가하지 않고 감소 시키려면 몇 가지 문자를 줄일 수 있습니다 uint64_t s(uint64_t n){for(uint64_t r=n;--n>r/n;);return n;}.
— Fors

@Fors — 멋진 접근 방식! 불행히도 1의 입력으로 0으로 나누지 않습니까? 또한 0을 입력하면 어떻게됩니까? 때문에 --n시 n==0-1, 이들 부호없는 값이다 것 때문에 -1 2⁶⁴-1 일 것이다.
— Todd Lehman

1
#define Z uint64_t ... 또는 typedef는 부부를 구할 것입니다
— technosaurus

@technosaurus — 아, 그렇습니다. 2. 감사합니다. :-)
— Todd Lehman

1
표현 n/++r/r은 정의되지 않은 동작을 가지고 있습니다 ....
— aschepler

4

골프 스크립트-14 자

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

가장 작은 수를 찾기 i적은 입력 이상 n에 대한 n < i*i. 을 반환 i - 1합니다.

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

입력이있는 샘플 호출에 대해 Golfscript도 모르는 사용자를위한 설명 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, 이전의 Golfscript 답변보다 3 자 짧습니다. 잘 하셨어요!
— Todd Lehman

입력에 대한 올바른 답변을 제공하도록이 문제를 해결하려면 1아마도 두 문자가 필요합니다.
— 피터 테일러

4

하스켈 147 138 134 128 바이트

세계에서 가장 짧은 코드는 아니지만 O (log n) 및 임의 크기의 숫자로 실행됩니다.

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)

sqrt (n)에 가장 적합한 근사값을 찾기 위해 [0..n] 범위의 이진 검색을 수행합니다. ungolfed 버전은 다음과 같습니다.

-- 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

편집 : "otherwise"절을 "True"의 짧은 버전으로 "0 <1"으로 바꾸고 g * g를 인라인하여 몇 바이트를 절약하여 2 바이트를 절약했습니다.

또한 O (sqrt (n))에 만족하면 간단히 할 수 있습니다.

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

35자를 위해, 그러나 그것은 얼마나 재미 있습니까?

편집 2 : min2Cycle 대신 쌍이 사전 순서로 정렬되어 있기 때문에 방금 인식했습니다. fst 맵, 나는 fst 할 수 있습니다. min2Cycle. 골프 코드에서 f $ map fst를 fst $ f로 바꾸면 4 바이트가 더 절약됩니다.

편집 3 : proudhaskeller 덕분에 6 바이트를 더 절약했습니다!


1
DIV와 당신이 바꿀 수 있습니다 (DIV × 2 + 렘 × 2) (X + 1)이, 당신의 "반"기능에서
— 자랑 haskeller

실제로 O (로그 n)이 49 개 문자 및 해결할 수있는 문제를 가지고있는 내 자신의 해결책을 가지고,하지만 난 단지 2 upvotes이 ;-( 그 이유를 이해하지 않습니다.
— 자랑 haskeller

4

JavaScript 91 88 86 : 속도에 최적화

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 : 속도에 최적화되지 않은

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

다음은 JSFiddle입니다. http://jsfiddle.net/rmadhuram/1Lnjuo4k/


1
PPCG에 오신 것을 환영합니다! 취소 선에 <s> 91 </ s> <s> 88 </ s>을 사용할 수 있습니다. 편집을하려고했지만 동시에 편집하고 있었으므로 그렇게하겠습니다.
— Rainbolt

1
또는 다음과 같이 41 자로 입력 할 수 있습니다.function s(n){for(a=1;++a*a<n;);return a}
— Rhubarb Custard

4

C 95 97

@Michaelangelo가 제안한 Typedef 편집

이것은 Heron 알고리즘의 간단한 구현이어야합니다. 유일한 단점은 정수 오버플로를 피하는 평균을 계산하는 것입니다.

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;
}

오버플로 방지 기능을 사용하면 문제없이 올바르게 작업 할 수있을뿐만 아니라 처음부터 그것에 대해 생각하고 테스트 할 수 있습니다. 확실히 감사합니다.
— Todd Lehman

BTW, 일부 CPU에서 얼마나 비싸게 나눌 수 있는지는 재밌습니다. 이 알고리즘은 abacus 알고리즘의 약 절반 단계로 실행되지만 Core i7 CPU에서 벤치마킹 할 때 abacus 알고리즘보다 약 5 배 느린 런타임을 갖습니다. 어쨌든 여기서는 런타임이 중요하지 않으며 크기 만 중요합니다. :) 정말 잘 했어 !!!
— Todd Lehman

4

C # 64 62 55

이것은 (그리고 수학에 끔찍합니다)이며 런타임은 단지 제안 일뿐이므로 선형 시간으로 실행되는 순진한 접근 방식을 수행했습니다.

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

( dotnetfiddle에서 테스트 )

물론 더 큰 입력의 경우에는 너무 느립니다.


1
? 로 변경 return i-1하여 캐릭터를 면도 할 수 있습니다 return--i.
— Todd Lehman

식에서 i*i<=a일반적인 유형의 정수 산술이 보장됩니까? (C #에 익숙하지 않습니다.) 그렇다면 C #에서 C와 같이 암시 적 정수 변환을 부울로 허용하면이를로 변경하여 하나 이상의 문자를 저장할 수 있습니다 a/i/i.
— Todd Lehman

1
@ToddLehman 실제로 Decimal곱셈 결과가 한 단계 지나갈 수 있기 때문에 오버플로를 피하기 위해 실제로 고정 소수점 산술 ( , 더 높은 최대 값 및 정밀도)이 발생합니다 UInt64.MaxValue. 그러나 C #에는 어쨌든 부울로의 암시 적 변환이 없습니다. return그래도 감사 할 수 있어야합니다 . 컴퓨터로 돌아 오면하겠습니다.
— Bob

3

클로저-51 또는 55 바이트

n에서 0까지의 모든 숫자를 확인하고 첫 번째 숫자는 where x^2 <= n입니다. 런타임은O(n - sqrt n)

이름 :

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

명명 된:

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

예:

(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 바이트 또는 38 자

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

여기에 시도 하십시오.


1
좋아, 그냥 멋지다. 잘 하셨어요! 17을 입력하고 Creep를 클릭 한 다음 Run을 클릭하면 4가 나타납니다! :)
— Todd Lehman

3

코브라-62

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

배치-74

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


3

J (10)

@Dennis 의 답변 에서 매우 영감을 얻었습니다 .

<.@%~^&1.5

그리고 약간 더 길지만 더 나은 성능을 제공합니다 (의심).

<.@(-:&.^.)

floor(halve under log)

실행하기 위해 들여 쓰기 된 부분이 입력됩니다.

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

주어진 정수에 대해 이것을 어떻게 수행합니까?
— Dennis

1

3

APL-12 자, 19 바이트

{⌊(⍵*1.5)÷⍵}

사용 예 :

{⌊(⍵*1.5)÷⍵}17

4를 반환

테스트 벡터

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

보고

1111 34 34255256 4294967296

온라인 시도

큰 감사 : 알고리즘에 대한 사용자 "ssdecontrol"


1
PPCG에 오신 것을 환영합니다! 일반적으로 APL은 문자 당 1 바이트로 점수를 매 깁니다. 챌린지에서 지정하지 않으면 UTF-8로 계산할 필요가 없습니다. 기존의 모든 인코딩은 괜찮으며 각 문자마다 단일 바이트를 사용하는 오래된 APL 코드 페이지가 있습니다. APL이 ASCII보다 이전의 사실은 ASCII가 아닌 문자를 사용하여 ASCII를 처벌하는 나쁜 이유입니다. ;) (
— Martin Ender

@MartinEnder 따뜻한 환영과 팁 감사합니다 :)
— QuantumKarl

1
0→ 1! 사용 Dyalog APL을 , 당신은 설정할 수 있습니다 ⎕DIV←1정확한 결과를 얻기 위해 (기본으로하는 많은 사용을).
— Adám

2

C99 (108 자)

다음은 Wikipedia 기사 의 알고리즘에서 채택한 C99의 자체 솔루션입니다 . 나는 다른 언어로 이것보다 훨씬 더 잘 할 수있을 것이라고 확신한다.

골프 :

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;}

부분적으로 골프 :

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;
}

언 골프 드 :

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
제안 : 필요 없음 a사용 n.
— edc65

아. 넵. 감사합니다. 원래 버전에서는 n반환하기 직전에 r ^ 2 <= n <(r + 1) ^ 2라는 어설 션 (표시되지 않음)을 만들 수 있도록 유지 관리했습니다 . 해당 어설 션을 생략하면 더 이상 n그대로 유지해야합니다 .
— Todd Lehman

@ edc65 — 지적 해 주셔서 다시 한 번 감사드립니다. 나는 그것을 반영하기 위해 코드를 업데이트하고 몇 가지 다른 골프 트릭을 추가했습니다. 또한 원래 어설 션을 추가하고 constungolfed 버전에서 n 을 만들었습니다 .
— Todd Lehman

2

JavaScript 73 81 (64 비트 숫자 요구 사항 준수)

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

알렉산드리아 알고리즘 의 헤론 구현 ...


좋은! 부호없는 64 비트 정수 입력에 모두 작동합니까?
— Todd Lehman

32 비트까지만 작동하는 것처럼 보일 수도 있습니다 ... 실망 스럽습니다 ...
— WallyWest

마지막 | 0은 임의의 값을 32 비트로 절단합니다. 대신 Math.floor를 사용하십니까?
— edc65

@ edc65 실제로 맞습니다. |0최대 32 비트에 영향을주는 반면 Math.floor64 비트에서는 더 효과적입니다 ... 코드를 업데이트하여 추가 8자를 입력해야합니다.
— WallyWest

@ edc65 방금 생각이 왔어요 ... ~ ~ x 64 비트에서 작동합니까?
— WallyWest

2

Powershell (52) Int32 (-2,147,483,648 ~ 2,147,483,647)로 제한

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

Powershell이 ​​마지막 테스트 케이스를 작동 시키려고 지금 비명을 지르고 있지만 Powershell은 파이프 라인 변수 $ _를 Int32로 사용하여 바람을 피우며 지금은 그 길을 찾을 수 없습니다.

따라서 지금은 답변을 제한하겠습니다. uint64를 처리하는 더 좋은 방법을 찾을 수 있다면 편집하겠습니다. (마지막 테스트 케이스는 Powershell의 일반적인 Int64 유형에 비해 너무 큽니다!)

다음은 몇 가지 테스트 사례입니다 (시간을 추적하는 데 사용 된 추가 출력이 약간 있음)

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

내 O ()를 모르지만 이것은 상당히 극적인 점프처럼 보입니다.


2

주의 사항 : 2011 년 현재 R은 64 비트 정수를 기본적으로 지원하지 않았습니다. 이러한 답변은 해당 기술에서 유효하지 않을 수 있지만 R은 지난 3 년 동안 많은 변화를 거쳤습니다.


R, 85

뉴턴의 방법을 사용하여 :

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)}

이차적으로 수렴합니다. 벤치마킹을 위해 변수에 함수를 할당하려면 +2 자 :

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

무차별 대입 :

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

그리고 같은 검사 :

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

저렴 / 화려한 지수 트릭 :

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

또한 내장 속도만큼 빠르지는 않지만 매우 빠릅니다.

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;}

나의 포스 제출의 번역. 느리지 만 정확합니다. O (√n). OS X (64 비트)에서 테스트되었습니다.


2

dc, 50 바이트

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

간격을두고 설명했다 :

               # 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

마지막 테스트 사례가 충돌 한 것 같습니다. 나는 그것을 고치려고 노력할 것이다.
— Joe

해결되었습니다. 이제 매우 큰 입력을 받아들입니다. 고의로 수정을 통해 처음에 추한 코드를 제거 할 수있었습니다.
— Joe

2

C, 139 (137) 136 바이트

코드 골프에 대한 첫 번째 시도. O(log n)추가 및 비트 시프트 만 사용하여 시간이 지남 에 따라 "효율적인"요구 사항에 맞는 C에서 가장 짧은 것 같습니다 . 나는 그것이 더 짧을 수 있다고 확신하지만 ...

a=32부분이로 변경되는 한 더 큰 정수 값에도 잘 작동 합니다 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;}

잘 하셨어요! 테스트하기 위해 실행하지는 않았지만 코드가 흥미로워 보입니다. 에 할당하는 (t++)대신 당신이 쓴 이유 t++가 r있습니까?
— Todd Lehman

1
@ToddLehman Nope, 그냥 꺼내는 것을 놓쳤다. 좋은 캐치!
— Chris

BTW, 나는 글쓰기를 피하는 방법을 좋아 합니다 . 어딘가에서 그 트릭을 배우거나 직접 발명 했습니까? a--+1a-- != UINT64_C(-1)
— Todd Lehman

1
@ToddLehman 감사합니다! 나는 그것을 스스로 알아 냈습니다.
— Chris

1

C-50 (글로벌없이 61)

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

공간을 절약하기 위해 전역 변수를 매개 변수 및 반환 값으로 사용합니다.

글로벌 버전 없음 :

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

1
전역 변수를 사용하는 것이 합법적이라고 생각하지 않습니다. 적어도 합법적으로 얼마나 오래 될 것인지 말하고 합법적 인 버전을 제공하십시오
— 자랑스런 Haskeller

@proud haskeller 전역 변수가 금지 된 이유는 무엇입니까?
— mantale

실행 가능한 프로그램 / 방법을 제공해야하므로 @mantal.
— Marciano.Andrade

@ Marciano.Andrade 코드가 실행 가능합니다.
— 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;
}

좋은! 어떻습니까 x+=(d<0)-0.5;... 5 문자를 더 절약합니까?
— Todd Lehman

BTW, 이것은 문제 설명에서 언급했듯이 함수 형태가 아닙니다 (그러나 있어야합니다). (좋아요, 기술적으로, 예, main함수입니다. 그러나 프로그램 내부에서 호출 f(y)할 수는 없습니다.)
— Todd Lehman

가장 안쪽의 괄호 쌍을 생략하고 while((d=x*x-y)>0.5)대신 쓸 수 있다고 생각합니다 while((d=(x*x-y))>0.5). 2 개 이상의 문자를 저장합니다. :)
— Todd Lehman

모든 0.5는 0.5로 변경 될 수 있습니다
— Yytsi
당사 사이트를 사용함과 동시에 당사의 쿠키 정책과 개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.