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


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_tuint32_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을 입력하면 어떻게됩니까? 때문에 --nn==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
01! 사용 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.