四个正方形在一起


19

拉格朗日的四平方定理告诉我们,任何自然数都可以表示为四平方数的和。您的任务是编写一个执行此操作的程序。

输入:自然数(10亿以下)

输出:四个数字的平方和等于该数字(顺序无关紧要)

注意:您不必进行暴力搜索!这里这里的细节。如果有一个函数可以解决此问题(我将确定),则不允许这样做。允许自动素函数和平方根。如果存在多个表示,则任何一个都可以。如果选择进行暴力破解,则必须在合理的时间内(3分钟)运行

样本输入

123456789

样本输出(都可以)

10601 3328 2 0
10601 3328 2

如果使我的代码更短,我可能会蛮力?
马丁·恩德

@ m.buettner是的,但它应该处理大量数字
qwr 2014年

@ m.buettner阅读该帖子,任何自然值低于10亿的东西
qwr 2014年

抱歉对不起。
马丁·恩德

2
@Dennis在这种情况下的自然数不包含
0。– qwr

Answers:


1

CJam,50个字节

li:NmF0=~2/#:J(_{;)__*N\-[{_mqJ/iJ*__*@\-}3*])}g+p

我的第三个(也是最后一个,我保证)答案。这种方法很大程度上基于primo的答案

CJam解释器中在线尝试。

用法

$ cjam 4squares.cjam <<< 999999999
[189 31617 567 90]

背景

  1. 看了primo的更新算法后,我不得不看一下CJam实现的得分:

    li{W):W;:N4md!}g;Nmqi)_{;(__*N\-[{_mqi__*@\-}3*])}g+2W#f*p
    

    只有58个字节!该算法在几乎恒定的时间内执行,并且对于的不同值没有太大变化N。让我们改变一下...

  2. 除了开始于floor(sqrt(N))递减,我们还可以开始于递减1。这样可以节省4个字节。

    li{W):W;:N4md!}g;0_{;)__*N\-[{_mqi__*@\-}3*])}g+2W#f*p
    
  3. 除了将其表示N为之外4**a * b,我们还可以将其表示为p**(2a) * b-其中p最小的素因数N-节省1个字节。

    li_mF0=~2/#:J_*/:N!_{;)__*N\-[{_mqi__*@\-}3*])}g+Jf*p
    
  4. 以前的修改可以让我们稍微改变执行(不接触算法本身):与其将N通过p**(2a)由繁衍的解决方案p**a,我们可以直接限制的倍数可能的解决方案p**a。这样可以再节省2个字节。

    li:NmF0=~2/#:J!_{;J+__*N\-[{_mqJ/iJ*__*@\-}3*])}g+`
    
  5. 不将第一个整数限制为的倍数会p**a节省一个额外的字节。

    li:NmF0=~2/#:J(_{;)__*N\-[{_mqJ/iJ*__*@\-}3*])}g+`
    

最终算法

  1. 查找ab使得N = p**(2a) * b,其中b是不是多p**2p是最小的首要因素N

  2. 设置j = p**a

  3. 设置k = floor(sqrt(N - j**2) / A) * A

  4. 设置l = floor(sqrt(N - j**2 - k**2) / A) * A

  5. 设置m = floor(sqrt(N - j**2 - k**2 - l**2) / A) * A

  6. 如果为N - j**2 - k**2 - l**2 - m**2 > 0,请设置j = j + 1并返回步骤3。

可以如下实现:

li:N          " Read an integer from STDIN and save it in “N”.                        ";
mF            " Push the factorization of “N”. Result: [ [ p1 a1 ] ... [ pn an ] ]    ";
0=~           " Push “p1” and “a1”. “p1” is the smallest prime divisor of “N”.        ";
2/#:J         " Compute p1**(a1/2) and save the result “J”.                           ";
(_            " Undo the first two instructions of the loop.                          ";
{             "                                                                       ";
  ;)_         " Pop and discard. Increment “J” and duplicate.                         ";
  _*N\-       " Compute N - J**2.                                                     ";
  [{          "                                                                       ";
    _mqJ/iJ*  " Compute K = floor(sqrt(N - J**2)/J)*J.                                ";
    __*@      " Duplicate, square and rotate. Result: K   K**2   N - J**2             ";
    \-        " Swap and subtract. Result: K   N - J**2 - K**2                        ";
  }3*]        " Do the above three times and collect in an array.                     ";
  )           " Pop the array. Result: N - J**2 - K**2 - L**2 - M**2                  ";
}g            " If the result is zero, break the loop.                                ";
+p            " Unshift “J” in [ K L M ] and print a string representation.           ";

基准测试

我已经在Intel Core i7-3770上的所有正整数(直到999,999,999)上运行了所有5个版本,测量了执行时间并计算了寻找解决方案所需的迭代次数。

下表显示了单个整数的平均迭代次数和执行时间:

Version               |    1    |    2    |    3    |    4    |    5
----------------------+---------+---------+---------+---------+---------
Number of iterations  |  4.005  |  28.31  |  27.25  |  27.25  |  41.80
Execution time [µs]   |  6.586  |  39.69  |  55.10  |  63.99  |  88.81
  1. primo的算法只有4次迭代和每个整数6.6 微秒,因此速度非常快。

  2. 从开始floor(sqrt(N))更有意义,因为这使我们剩下的三个平方和的值较小。不出所料,从1开始慢很多。

  3. 这是一个不好的好主意的经典例子。为了实际减少代码大小,我们依靠mF,将整数分解N。尽管版本3所需的迭代次数少于版本2,但实际使用起来要慢得多。

  4. 尽管算法没有改变,但是版本4慢得多。这是因为它在每次迭代中执行附加的浮点除法和整数乘法。

  5. 对于输入N = p**(2a) ** b,算法5将需要(k - 1) * p**a + 1迭代,其中k是算法4所需的迭代次数。如果k = 1a = 0,则没有区别。

    但是,任何形式的输入都4**a * (4**c * (8 * d + 7) + 1)可能执行得很差。对于初始值j = p**aN - 4**a = 4**(a + c) * (8 * d + 7),因此它不能被表示为三个平方的总和。因此,k > 1至少p**a需要迭代。

    值得庆幸的是,primo的原始算法非常快且速度非常快N < 1,000,000,000。我可以手工找到的最坏情况是265,289,728 = 4**10 * (4**1 * (7 * 8 + 7) + 1),它需要6,145次迭代。我的机器上的执行时间少于300毫秒。平均而言,此版本比primo算法的实现慢13.5倍。


“ 我们可以将其表示N4**a * b,而不是表示为p**(2a) * b。” 这实际上是一种改进。我本来希望包括在内,但它要长得多(理想的情况是找到最大的完美平方因数)。“以1开头并递增将节省4个字节。” 这绝对慢。任何给定范围的运行时间是其4-5倍。“直到999,999,999的所有正整数都花了24.67小时,平均执行时间为每整数0.0888毫秒。” Perl只花了2.5小时来处理整个范围,而Python的翻译速度则快了10倍;)
primo 2014年

@primo:是的,你是对的。除以p**a是一种改进,但这只是很小的一个。从1开始,除以最大的完美平方因数会有很大的不同;从平方根的整数部分开始仍然是一个改进。实现它只会花费另外两个字节。糟糕的执行时间似乎是由于我的进步,而不是CJam。我将针对所有算法(包括您提出的算法)重新运行测试,计算迭代次数,而不是测量墙时间。让我们看多久需要...
丹尼斯

查找最大平方因数仅需花费2个额外字节?!这是什么魔法?
2014年

@primo:如果整数在堆栈上,1\则将其交换为1(累加器),mF推动其因式分解,并将{~2/#*}/每个素因数提高到其指数除以2,然后将其乘以累加器。对于算法的直接实现,仅增加2个字节。细微的差异主要是由于我必须找到4的指数的尴尬方式,因为CJam没有(似乎)有一个while循环……
丹尼斯

无论如何,基准测试完成了。在没有找到最大平方因子的情况下分解所有1,000,000整数所需的迭代总数为4,004,829,417,执行时间为1.83小时。除以最大平方因数可将迭代次数减少到3,996,724,799,但将时间增加到6.7小时。看起来进行分解比查找平方需要更多的时间……
丹尼斯2014年

7

分数:156 98个分数

由于这是经典的数论问题,因此解决此问题的方法比使用数字更好!

37789/221 905293/11063 1961/533 2279/481 57293/16211 2279/611 53/559 1961/403 53/299 13/53 1/13 6557/262727 6059/284321 67/4307 67/4661 6059/3599 59/83 1/59 14279/871933 131/9701 102037079/8633 14017/673819 7729/10057 128886839/8989 13493/757301 7729/11303 89/131 1/89 31133/2603 542249/19043 2483/22879 561731/20413 2483/23701 581213/20687 2483/24523 587707/21509 2483/24797 137/191 1/137 6215941/579 6730777/965 7232447/1351 7947497/2123 193/227 31373/193 23533/37327 5401639/458 229/233 21449/229 55973/24823 55973/25787 6705901/52961 7145447/55973 251/269 24119/251 72217/27913 283/73903 281/283 293/281 293/28997 293/271 9320827/58307 9831643/75301 293/313 28213/293 103459/32651 347/104807 347/88631 337/347 349/337 349/33919 349/317 12566447/68753 13307053/107143 349/367 33197/349 135199/38419 389/137497 389/119113 389/100729 383/389 397/383 397/39911 397/373 1203/140141 2005/142523 2807/123467 4411/104411 802/94883 397/401 193/397 1227/47477 2045/47959 2863/50851 4499/53743 241/409 1/241 1/239

接受2 n ×193 形式的输入,并输出3 a ×5 b ×7 c ×11 d。如果你有一个在3分钟内可能会遇到真正的好解释。也许。

...好吧,不是真的。在FRACTRAN中,这似乎是一个有趣的问题,我不得不尝试一下。显然,这不是解决问题的合适方法,因为它没有时间要求(蛮力),几乎没有打高尔夫球的机会,但是我想我将其发布在这里,因为并不是每天都有Codegolf问题可以在FRACTRAN中完成;)

暗示

该代码等效于以下伪Python:

a, b, c, d = 0, 0, 0, 0

def square(n):
    # Returns n**2

def compare(a, b):
    # Returns (0, 0) if a==b, (1, 0) if a<b, (0, 1) if a>b

def foursquare(a, b, c, d):
    # Returns square(a) + square(b) + square(c) + square(d)

while compare(foursquare(a, b, c, d), n) != (0, 0):
    d += 1

    if compare(c, d) == (1, 0):
        c += 1
        d = 0

    if compare(b, c) == (1, 0):
        b += 1
        c = 0
        d = 0

    if compare(a, b) == (1, 0):
        a += 1
        b = 0
        c = 0
        d = 0

7

Mathematica 61 66 51

显示了三种方法。只有第一种方法可以满足时间要求。


1-FindInstance(51个字符)

这将返回方程的单个解。

FindInstance[a^2 + b^2 + c^2 + d^2 == #, {a, b, c, d}, Integers] &

例子和时间

FindInstance[a^2 + b^2 + c^2 + d^2 == 123456789, {a, b, c, d}, Integers] // AbsoluteTiming

{0.003584,{{a-> 2600,b-> 378,c-> 10468,d-> 2641}}}

FindInstance[a^2 + b^2 + c^2 + d^2 == #, {a, b, c, d}, Integers] &[805306368]

{0.004437,{{a-> 16384,b-> 16384,c-> 16384,d-> 0}}}


2个整数分区

这也可以,但是太慢而不能满足速度要求。

f@n_ := Sqrt@IntegerPartitions[n, {4}, Range[0, Floor@Sqrt@n]^2, 1][[1]]

Range[0, Floor@Sqrt@n]^2是所有平方的集合,小于平方根n(分区中可能的最大平方)。

{4}要求n由上述正方形集中的由4个元素组成的整数分区。

1中的函数IntegerPartitions返回第一个解决方案。

[[1]]拆下外部支架;解决方案作为一组一个元素返回。


f[123456]

{348,44,20,4}


3-电源表示

PowerRepresentations返回4平方问题的所有解决方案。它还可以解决其他能力的总和。

PowersRepresentations在5秒内返回181种方法,将123456789表示为4个平方的和:

n= 123456;
PowersRepresentations[n, 4, 2] //AbsoluteTiming

溶胶

但是,对于其他金额而言,它太慢了。


哇,Mathematica的蛮力很快。IntegerPartitions做的事情比尝试每个组合(例如DFT卷积在集合上)要聪明得多吗?顺便说一句,规格要求输入数字,而不是平方。
xnor 2014年

我认为Mathematica使用蛮力,但可能已进行了优化IntegerPartitions。从计时中可以看出,速度的变化很大,这取决于第一个(最大)数字是否接近的平方根n。感谢您在早期版本中发现违反规范的情况。
DavidC 2014年

你能基准f[805306368]吗?在不除以4的幂的情况下,我的解决方案在999999999上花了0.05 s的时间;我在5分钟后放弃了805306368的基准...
丹尼斯

f[805306368]{16384, 16384, 16384}21分钟后返回。我用{3}代替了{4}。经过几个小时的运行后,尝试用4个非零平方之和解决该问题的尝试失败。
DavidC

我没有使用Mathematica的权限,但是从我在文档中心阅读的内容来看,它也IntegerPartitions[n,4,Range[Floor@Sqrt@n]^2应该可以正常工作。但是,我认为您不应该使用方法1进行评分,因为它不符合问题中指定的时间限制。
丹尼斯

7

Perl- 116个字节 87个字节(请参阅下面的更新)

#!perl -p
$.<<=1,$_>>=2until$_&3;
{$n=$_;@a=map{$n-=$a*($a-=$_%($b=1|($a=0|sqrt$n)>>1));$_/=$b;$a*$.}($j++)x4;$n&&redo}
$_="@a"

将shebang视为一个字节,添加了换行符以保持水平。

组合式 提交方式。

平均(最糟的)案例复杂度似乎是O(log n) O(n 0.07。我没有发现运行速度低于0.001s,并且检查了整个范围900000000-999999999。如果您发现需要更长的时间,大约〜0.1s或更长时间,请告诉我。


样品用量

$ echo 123456789 | timeit perl four-squares.pl
11110 157 6 2

Elapsed Time:     0:00:00.000

$ echo 1879048192 | timeit perl four-squares.pl
32768 16384 16384 16384

Elapsed Time:     0:00:00.000

$ echo 999950883 | timeit perl four-squares.pl
31621 251 15 4

Elapsed Time:     0:00:00.000

对于其他提交者,最后两个似乎是最坏的情况。在这两种情况下,显示的解决方案实际上都是检查的第一件事。对于123456789,这是第二个。

如果要测试值的范围,可以使用以下脚本:

use Time::HiRes qw(time);

$t0 = time();

# enter a range, or comma separated list here
for (1..1000000) {
  $t1 = time();
  $initial = $_;
  $j = 0; $i = 1;
  $i<<=1,$_>>=2until$_&3;
  {$n=$_;@a=map{$n-=$a*($a-=$_%($b=1|($a=0|sqrt$n)>>1));$_/=$b;$a*$i}($j++)x4;$n&&redo}
  printf("%d: @a, %f\n", $initial, time()-$t1)
}
printf('total time: %f', time()-$t0);

最好通过管道传输到文件。该范围1..1000000在我的计算机上花费大约14s(每秒71000个值),并且999000000..1000000000花费大约20s(每秒50000个值),与O(log n)平均复杂度一致。


更新资料

编辑:事实证明,该算法与心理计算器至少一个世纪以来一直使用的算法非常相似。

自从最初发布以来,我已经检查了1..1000000000范围内的每个值。值699731569显示了“最坏情况”的行为,该值在得出解决方案之前测试了总共190种组合。如果您认为190是一个很小的常数(我当然会这样做),则可以将所需范围内的最坏情况视为O(1)。也就是说,与从巨型表中查找解决方案一样快,并且平均而言,可能更快。

不过另一件事。经过190次迭代后,大于144400的任何都没有超过第一次通过。广度优先遍历的逻辑毫无价值-甚至没有使用。上面的代码可以大大缩短:

#!perl -p
$.*=2,$_/=4until$_&3;
@a=map{$=-=$%*($%=$=**.5-$_);$%*$.}$j++,(0)x3while$=&&=$_;
$_="@a"

仅执行搜索的第一遍。我们确实需要确认144400以下没有任何值需要第二遍,但是:

for (1..144400) {
  $initial = $_;

  # reset defaults
  $.=1;$j=undef;$==60;

  $.*=2,$_/=4until$_&3;
  @a=map{$=-=$%*($%=$=**.5-$_);$%*$.}$j++,(0)x3while$=&&=$_;

  # make sure the answer is correct
  $t=0; $t+=$_*$_ for @a;
  $t == $initial or die("answer for $initial invalid: @a");
}

简而言之,对于1..1000000000范围,存在一个接近恒定的时间解,您正在研究它。


更新更新

@Dennis和我对该算法做了一些改进。如果您有兴趣,可以按照下面的评论和后续讨论中的进度进行。所需范围的平均迭代次数已从刚刚超过4次降至1.229,测试1..1000000000所有值所需的时间已从18m 54s减少到2m 41s。最坏的情况以前需要190次迭代。现在最坏的情况是854382778,只需要21个

最终的Python代码如下:

from math import sqrt

# the following two tables can, and should be pre-computed

qqr_144 = set([  0,   1,   2,   4,   5,   8,   9,  10,  13,
                16,  17,  18,  20,  25,  26,  29,  32,  34,
                36,  37,  40,  41,  45,  49,  50,  52,  53,
                56,  58,  61,  64,  65,  68,  72,  73,  74,
                77,  80,  81,  82,  85,  88,  89,  90,  97,
                98, 100, 101, 104, 106, 109, 112, 113, 116,
               117, 121, 122, 125, 128, 130, 133, 136, 137])

# 10kb, should fit entirely in L1 cache
Db = []
for r in range(72):
  S = bytearray(144)
  for n in range(144):
    c = r

    while True:
      v = n - c * c
      if v%144 in qqr_144: break
      if r - c >= 12: c = r; break
      c -= 1

    S[n] = r - c
  Db.append(S)

qr_720 = set([  0,   1,   4,   9,  16,  25,  36,  49,  64,  81, 100, 121,
              144, 145, 160, 169, 180, 196, 225, 241, 244, 256, 265, 289,
              304, 324, 340, 361, 369, 385, 400, 409, 436, 441, 481, 484,
              496, 505, 529, 544, 576, 580, 585, 601, 625, 640, 649, 676])

# 253kb, just barely fits in L2 of most modern processors
Dc = []
for r in range(360):
  S = bytearray(720)
  for n in range(720):
    c = r

    while True:
      v = n - c * c
      if v%720 in qr_720: break
      if r - c >= 48: c = r; break
      c -= 1

    S[n] = r - c
  Dc.append(S)

def four_squares(n):
  k = 1
  while not n&3:
    n >>= 2; k <<= 1

  odd = n&1
  n <<= odd

  a = int(sqrt(n))
  n -= a * a
  while True:
    b = int(sqrt(n))
    b -= Db[b%72][n%144]
    v = n - b * b
    c = int(sqrt(v))
    c -= Dc[c%360][v%720]
    if c >= 0:
      v -= c * c
      d = int(sqrt(v))

      if v == d * d: break

    n += (a<<1) - 1
    a -= 1

  if odd:
    if (a^b)&1:
      if (a^c)&1:
        b, c, d = d, b, c
      else:
        b, c = c, b

    a, b, c, d = (a+b)>>1, (a-b)>>1, (c+d)>>1, (c-d)>>1

  a *= k; b *= k; c *= k; d *= k

  return a, b, c, d

它使用两个预先计算的校正表,一个校正表,大小为10kb,另一个校正表为253kb。上面的代码包括这些表的生成器函数,尽管这些函数可能应该在编译时进行计算。

可以在以下位置找到具有更适中的校正表的版本:http : //codepad.org/1ebJC2OV该版本每个术语平均需要进行1.620次迭代,最坏的情况是38次,并且整个范围的运行时间约为3m 21s。通过按位and进行b校正而不是取模,可以节省一点时间。


改进之处

偶数比奇数更有可能产生解决方案。
链接到先前的心理计算文章指出,如果在除去所有四个因子之后,要分解的值是偶数,则可以将该值除以2,然后重新构造解:

尽管这对于心理计算可能有意义(较小的值往往更易于计算),但在算法上并没有太大意义。如果拿256随机4元组,并检查平方和模8,你会发现的值135,和7分别平均达到32倍。但是,值26分别达到48次。将奇数值乘以2可以平均减少33%的迭代次数。重建如下:

需要注意的是,ab以及cd都具有相同的奇偶性,但是,如果根本找不到解决方案,则可以保证存在适当的排序。

不需要的路径不需要检查。
在选择第二个值b之后,考虑到任何给定模的可能二次残差,解决方案可能已经不存在。可以通过将b的值递减可能导致求解的最小量来“校正” b,而不是进行任何检查或进入下一个迭代。两个校正表存储这些值,一个用于b,另一个用于c。使用较高的模(更准确地说,使用具有相对较少的二次残基的模)将导致更好的改进。值a不需要任何校正;通过将n修改为偶数,一个有效。


1
这难以置信!最终的算法可能是所有答案中最简单的算法,但它只需要190次迭代就可以了……
丹尼斯

@丹尼斯如果没有其他地方提到我,我将感到非常惊讶。似乎太简单了,它已经被忽视了。
2014年

1.我很好奇:您的复杂度分析中的任何测试值是否都需要广度优先遍历?2.您链接到的Wikipedia文章有点令人困惑。它提到了Rabin-Shallit算法,但提供了一个完全不同的示例。3.有趣的是,什么时候确切地说Rabin-Shallit算法的性能会胜过您的算法,我想素数测试在实践中会相当昂贵。
丹尼斯

1.没有一个。2.这是我获得信息的地方(即该算法存在);我还没有看过分析,甚至没有看过这篇论文。3.曲线在1e60左右变得如此陡峭,以至于O(log²n)的 “速度”有多慢都无关紧要,它仍会在该点处相交。
primo

1
问题中的第二个链接说明了如何实现Rabin-Shallit,但没有讨论复杂性。关于MathOverflow的答案很好地总结了本文。顺便说一句,您重新发现了Gottfried Ruckle在1911年使用的算法(链接)。
丹尼斯

6

Python 3(177)

N=int(input())
k=1
while N%4<1:N//=4;k*=2
n=int(N**.5)
R=range(int(2*n**.5)+1)
print([(a*k,b*k,c*k,d*k)for d in R for c in R for b in R for a in[n,n-1]if a*a+b*b+c*c+d*d==N][0])

在我们将输入减少N为不能被4整除之后,它必须表示为四个平方的总和,其中一个是最大可能值,a=int(N**0.5)或者小于四个可能的值,仅剩下一小部分用于其他三个平方的总和照顾。这大大减少了搜索空间。

这是以后的证明,此代码总能找到解决方案。我们希望找到一个aso,它n-a^2是三个平方的和。根据勒让德的三平方定理,一个数字是三个平方的和,除非它是形式4^j(8*k+7)。特别地,这样的数字是0或3(模4)。

我们显示没有两个连续的a函数可以使剩余量N-a^2对于两个连续的值都具有这样的形状。我们可以通过简单地制作一个a和取N4 为模的表来做到这一点,请注意,N%4!=0因为我们从中提取了4的所有幂N

  a%4= 0123
      +----
     1|1010
N%4= 2|2121  <- (N-a*a)%4
     3|3232

因为没有连续两次a给出(N-a*a)%4 in [0,3],所以其中之一可以安全使用。所以,我们贪婪地使用尽可能nn^2<=N,和n-1。因为N<(n+1)^2N-a^2要表示为三个平方的和的余数最多(n+1)^2 -(n-1)^2等于4*n。因此,仅检查不超过的值就足够了2*sqrt(n),这恰好是range R

通过在单个解决方案之后停止,计算而不是迭代最后一个值d并仅在值中搜索,可以进一步优化运行时间b<=c<=d。但是,即使没有这些优化,我也可以在45秒内发现机器上最差的情况。

“ for in R中的x”的链很不幸。可以通过字符串替换或替换来缩短它,方法是遍历编码(a,b,c,d)的单个索引。导入itertools实在不值得。

编辑:int(2*n**.5)+1从更改为2*int(n**.5)+2使参数更整洁,相同字符数。


这对我不起作用……5 => (2, 1, 0, 0)
哈里·比德尔2014年

奇怪,它对我5 => (2, 1, 0, 0)有用:我在Ideone 3.2.3或Idle 3.2.2上运行。你得到了什么?
xnor 2014年

1
@xnor BritishColour获取5 => (2, 1, 0, 0)。你甚至看过评论吗?(现在我们连续有3条包含该代码段的注释。我们可以保持连胜吗?)
贾斯汀

@Quincunx如果我们要解密5 => (2, 1, 0, 0),那就意味着2^2 + 1^2 + 0^2 + 0^2 = 5。所以,是的,我们可以。
Rebmu博士2014年

1
Quincunx,我阅读了@BritishColour的评论,据我所知,它5 => (2, 1, 0, 0)是正确的。问题中的示例认为0 ^ 2 = 0是有效的平方数。因此,我解释了(就像我认为xnor所做的那样)英国色彩还有其他东西。英国色,因为您没有再回答,所以我们可以假设您确实得到了2,1,0,0吗?
级圣河

5

CJam91 90 74 71字节

q~{W):W;:N4md!}gmqi257:B_**_{;)_[Bmd\Bmd]_N\{_*-}/mq_i@+\1%}g{2W#*}%`\;

紧凑,但是比我的其他方法慢。

在线尝试!粘贴代码,在“ 输入中键入所需的整数,然后单击“运行”

背景

这篇文章开始是一个99字节的GolfScript答案。尽管仍有改进的空间,但是GolfScript缺少内置的sqrt功能。我将GolfScript版本保留到第5版,因为它与CJam版本非常相似。

但是,自第6版以来的优化要求在GolfScript中没有可用的运算符,因此,我决定放弃竞争性较差(且速度较慢)的版本,而不是针对两种语言分别发布说明。

实现的算法通过蛮力计算数字:

  1. 为了输入m,找到NW这样m = 4**W * N

  2. 设置i = 257**2 * floor(sqrt(N/4))

  3. 设置i = i + 1

  4. 查找j, k, l这样的整数i = 257**2 * j + 257 * k + l,其中k, l < 257

  5. 检查是否d = N - j**2 - k**2 - l**2是一个完美的正方形。

  6. 如果不是,请返回步骤3。

  7. 打印2**W * j, 2**W * k, 2**W * l, 2**W * sqrt(m)

例子

$ TIME='\n%e s' time cjam lagrange.cjam <<< 999999999
[27385 103 15813 14]
0.46 s
$ TIME='\n%e s' time cjam lagrange.cjam <<< 805306368
[16384 16384 0 16384]
0.23 s

时间对应于Intel Core i7-4700MQ。

怎么运行的

q~              " Read and interpret the input. ";
{
  W):W;         " Increment “W” (initially -1). ";
  :N            " Save the integer on the stack in “N”. ';
  4md!          " Push N / 4 and !(N % 4). ";
}g              " If N / 4 is an integer, repeat the loop.
mqi             " Compute floor(sqrt(N/4)). ";
257:B_**        " Compute i = floor(sqrt(N)) * 257**2. ";
_               " Duplicate “i” (dummy value). ";
{               " ";
  ;)_           " Pop and discard. Increment “i”. ";
  [Bmd\Bmd]     " Push [ j k l ], where i = 257**2 * j + 257 * k + l and k, l < 257. ";
  _N\           " Push “N” and swap it with a copy of [ j k l ]. ";
  {_*-}/        " Compute m = N - j**2 - k**2 - l**2. ";
  mq            " Compute sqrt(m). ";
  _i            " Duplicate sqrt(m) and compute floor(sqrt(m)). ";
  @+\           " Form [ j k l floor(sqrt(m)) ] and swap it with sqrt(m). ";
  1%            " Check if sqrt(m) is an integer. ";
}g              " If it is, we have a solution; break the loop. ";
{2W#*}%         " Push 2**W * [ j k l sqrt(m) ]. ";
`\;             " Convert the array into a string and discard “i”. ";

2

C,228

这基于Wikipedia页面上的算法,该算法是O(n)蛮力。

n,*l,x,y,i;main(){scanf("%d",&n);l=calloc(n+1,8);
for(x=0;2*x*x<=n;x++)for(y=x;(i=x*x+y*y)<=n;y++)l[2*i]=x,l[2*i+1]=y;
for(x=0,y=n;;x++,y--)if(!x|l[2*x+1]&&l[2*y+1]){
printf("%d %d %d %d\n",l[2*x],l[2*x+1],l[2*y],l[2*y+1]);break;}}

2

GolfScript,133个 130 129字节

~{.[4*{4/..4%1$!|!}do])\}:r~,(2\?:f;{{..*}:^~4-1??n*,}:v~)..
{;;(.^3$\-r;)8%!}do-1...{;;;)..252/@252%^@^@+4$\-v^@-}do 5$]{f*}%-4>`

很快,但是很长。换行符可以删除。

在线尝试。请注意,在线口译员有5秒的时间限制,因此它可能不适用于所有号码。

背景

该算法利用了勒让德的三平方定理,该定理指出每个自然数n都不是形式

                                                                   n = 4 ** a *(8b + 7)

可以表示为三个平方的总和。

该算法执行以下操作:

  1. 将数字表示为4**i * j

  2. 找到最大的整数k,使得k**2 <= jj - k**2满足勒的三平方定理的假设。

  3. 设置i = 0

  4. 检查是否j - k**2 - (i / 252)**2 - (i % 252)**2是一个完美的正方形。

  5. 如果不是,请增加i并返回到步骤4。

例子

$ TIME='%e s' time golfscript legendre.gs <<< 0
[0 0 0 0]
0.02 s
$ TIME='%e s' time golfscript legendre.gs <<< 123456789
[32 0 38 11111]
0.02 s
$ TIME='%e s' time golfscript legendre.gs <<< 999999999
[45 1 217 31622]
0.03 s
$ TIME='%e s' time golfscript legendre.gs <<< 805306368
[16384 0 16384 16384]
0.02 s

时间对应于Intel Core i7-4700MQ。

怎么运行的

~              # Interpret the input string. Result: “n”
{              #
  .            # Duplicate the topmost stack item.
  [            #
    4*         # Multiply it by four.
    {          #
      4/       # Divide by four.
      ..       # Duplicate twice.
      4%1$     # Compute the modulus and duplicate the number.
      !|!      # Push 1 if both are truthy.
    }do        # Repeat if the number is divisible by four and non-zero.
  ]            # Collect the pushed values (one per iteration) into an array.
  )\           # Pop the last element from the array and swap it with the array.
}:r~           # Save this code block as “r” and execute it.
,(2\?          # Get the length of the array, decrement it and exponentiate.
:f;            # Save the result in “f”.
               # The topmost item on the stack is now “j”, which is not divisible by 
               # four and satisfies that n = f**2 * j.
{              #
  {..*}:^~     # Save a code block to square a number in “^” and execute it.
  4-1??        # Raise the previous number to the power of 1/4.
               # The two previous lines compute (x**2)**(1/4), which is sqrt(abs(x)).
  n*,          # Repeat the string "\n" that many times and compute its length.
               # This casts to integer. (GolfScript doesn't officially support Rationals.)
}:v~           # Save the above code block in “v” and execute it.
)..            # Undo the first three instructions of the loop.
{              #
   ;;(         # Discard two items from the stack and decrement.
   .^3$\-      # Square and subtract from “n”.
   r;)8%!      # Check if the result satisfies the hypothesis of the three-square theorem.
}do            # If it doesn't, repeat the loop.
-1...          # Push 0 (“i”) and undo the first four instructions of the loop.
{              #
  ;;;)         # Discard two items from the stack and increment “i”.
  ..252/@252%  # Push the digits of “i” in base 252.
  ^@^@+4$\-    # Square both, add and subtract the result 
  v^@-         # Take square root, square and compare.
}do            # If the difference is a perfect square, break the loop.
5$]            # Duplicate the difference an collect the entire stack into an array.
{f*}%          # Multiply very element of the array by “f”.
-4>            # Reduce the array to its four last elements (the four numbers).
`              # Convert the result into a string.

1
我不明白j-k-(i/252)-(i%252)。从您的评论(我实际上无法阅读代码)看来,您的意思是j-k-(i/252)^2-(i%252)^2。顺便说一句,相当于j-k-(i/r)^2-(i%r)^2r = sqrt(k)可以节省一些字符(即使在我的C程序中,即使k = 0也似乎没有问题。)
Level River St

@steveverrill:是的,我犯了一个错误。感谢您的关注。应该是j-k^2-(i/252)^2-(i%252)^2。我仍在等待OP澄清0是否为有效输入。您的程序提供1414 -nan 6 4.000000输入0
丹尼斯2014年

我正在谈论使用勒让德定理的新程序,但尚未发布。看起来当我等于k = 0时,它永远不会用%或/调用代码,这就是为什么它不会引起问题。当我发布时您会看到。很高兴您运行了我的旧程序。您是否有内存可以在第1版中构建完整的2GB表,并且用了多长时间?
级圣河

是的,优化时C编译器的行为可能会出乎意料。在GolfScript中,0/=>崩溃!:P我已经在笔记本电脑(i7-4700MQ,8 GiB RAM)上运行了rev 1。平均而言,执行时间为18.5秒。
丹尼斯

哇,包括建立桌子在内,那是18.5秒吗?我的机器花了2分钟以上。我可以看到问题是Windows内存管理。与其立即给程序提供所需的2GB空间,不如将其分成小块,所以它必须做很多不必要的交换,直到分配了完整的2GB空间为止。实际上,根据用户输入搜索答案要快得多,因为到那时,该程序就不必乞求内存了。
级圣河

1

启1:C,190

a,z,m;short s[15<<26];p(){m=s[a=z-a];printf("%d %f ",m,sqrt(a-m*m));}
main(){m=31727;for(a=m*m;--a;s[z<m*m?z:m*m]=a%m)z=a/m*(a/m)+a%m*(a%m);scanf("%d",&z);for(;a*!s[a]||!s[z-a];a++);p();p();}

这比rev 0还要占用更多的内存。相同的原理:对于所有可能的2平方和(对于不是两个平方和的数字,则为0)构建一个具有正值的表,然后进行搜索。

在此版本中,使用short而不是char存储命中数组,因此我可以在表中存储一对正方形之一的根,而不仅仅是标记。由于p不需要循环,因此大大简化了功能(用于解码2个平方的和)。

Windows在阵列上有2GB的限制。我可以弄清楚short s[15<<26]其中包含1006632960个元素的数组,足以符合规范。不幸的是,总的程序运行时间规模仍然超过2GB和(尽管调整操作系统设置),我一直无法运行在该尺寸(虽然它在理论上是可能的)。我能做的最好的是short s[14<<26](939524096元)m*m必须是严格小于此值(30651 ^ 2 = 939483801。)但是,该程序可以完美运行,并且可以在没有此限制的任何OS上运行。

非高尔夫代码

a,z,m;
short s[15<<26];     
p(){m=s[a=z-a];printf("%d %f ",m,sqrt(a-m*m));}      
main(){       
 m=31727;             
 for(a=m*m;--a;s[z<m*m?z:m*m]=a%m)   //assignment to s[] moved inside for() is executed after the following statement. In this rev excessively large values are thrown away to s[m*m].
   z=a/m*(a/m)+a%m*(a%m);            //split a into high and low half, calculate h^2+l^2.                                  
 scanf("%d",&z); 
 for(;a*!s[a]||!s[z-a];a++);         //loop until s[a] and s[z-a] both contain an entry. s[0] requires special handling as s[0]==0, therefore a* is included to break out of the loop when a=0 and s[z] contains the sum of 2 squares.
 p();                                //print the squares for the first sum of 2 squares 
 p();}                               //print the squares for the 2nd sum of 2 squares (every time p() is called it does a=z-a so the two sums are exchanged.) 

版本0 C,219

a,z,i,m;double t;char s[1<<30];p(){for(i=t=.1;(m=t)-t;i++)t=sqrt(a-i*i);printf("%d %f ",i-1,t);}
main(){m=1<<15;for(a=m*m;--a;){z=a/m*(a/m)+a%m*(a%m);s[z<m*m?z:0]=1;}scanf("%d",&z);for(;1-s[a]*s[z-a];a++);p();a=z-a;p();}

这是一个渴望记忆的野兽。它需要一个1GB的数组,计算2个正方形的所有可能的总和,并在数组中为每个正方形存储一个标志。然后,对于用户输入z,它将在数组中搜索2个平方a和za的两个和。

p然后该函数重新构造用于生成2个平方a和的原始平方z-a并进行打印,每对中的第一个作为整数,第二个作为双精度(如果必须为整数,则需要再加上两个字符,t> m=t。)

该程序需要花费几分钟来构建平方和表(我认为这是由于内存管理问题,我看到内存分配缓慢上升,而不是像人们期望的那样上升。)但是一旦完成产生答案的速度非常快(如果要计算多个数字,则scanf可以将循环的程序放在后面。

非高尔夫代码

a,z,i,m;
double t;
char s[1<<30];                              //handle numbers 0 up to 1073741823
p(){
 for(i=t=.1;(m=t)-t;i++)t=sqrt(a-i*i);      //where a contains the sum of 2 squares, search until the roots are found
 printf("%d %f ",i-1,t);}                   //and print them. m=t is used to evaluate the integer part of t. 

main(){       
 m=1<<15;                                   //max root we need is sqrt(1<<30);
 for(a=m*m;--a;)                            //loop m*m-1 down to 1, leave 0 in a
   {z=a/m*(a/m)+a%m*(a%m);s[z<m*m?z:0]=1;}  //split a into high and low half, calculate h^2+l^2. If under m*m, store flag, otherwise throw away flag to s[0]
 scanf("%d",&z);
 for(;1-s[a]*s[z-a];a++);                   //starting at a=0 (see above) loop until flags are found for sum of 2 squares of both (a) and (z-a)
 p();                                       //reconsitute and print the squares composing (a)
 a=z-a;                                     //assign (z-a) to a in order to...
 p();}                                      //reconsitute and print the squares composing (z-a)  

输出示例

首先是每个问题。第二个被选为难以搜索的一个。在这种情况下,程序必须搜索多达8192 ^ 2 + 8192 ^ 2 = 134217728,但是一旦构建了表格,只需花费几秒钟的时间。

123456789
0 2.000000 3328 10601.000000

805306368
8192 8192.000000 8192 24576.000000

您不应该为sqrt添加原型吗?
edc65

@ edc65我正在使用GCC编译器(适用于Linux,但是我在Windows机器上安装了Cygwin Linux环境。)这意味着我不需要放入#include <stdio.h>(用于scanf / printf)或#include <math.h>(用于sqrt)。自动链接必要的库。我为此要感谢丹尼斯(他在这个问题上告诉我codegolf.stackexchange.com/a/26330/15599),这是我有过的最好的高尔夫技巧。
级圣河

我已经想知道为什么亨特·沃普斯出现在链接的问题中。:)顺便说一句,我不知道GCC在Windows上使用了什么,但是无论有没有,GNU链接器都不会自动链接数学库include。要在Linux上编译,您需要标记-lm
Dennis

@Dennis这很有趣,它包括stdio和其他几个库,但不能mathinclude?据我了解,如果您放置了编译器标志,则仍然不需要include吗?很好,它对我有用,所以我没有抱怨,再次感谢您的提示。顺便说一句,我希望能够张贴勒让德定理的一个完全不同的答案趁势(但它仍然会使用sqrt。)
电平江街

-lm影响链接器,而不影响编译器。gcc选择不要求其“了解”功能的原型,因此无论是否包含包含项,它都可以使用。但是,头文件仅提供函数原型,而不提供函数本身。在Linux(显然不是Windows)上,数学库libm不是标准库的一部分,因此您必须指示ld链接到它。
丹尼斯

1

Mathematica,138个字符

因此,事实证明,这会对edc65(例如805306368)指出的某些输入产生负面和虚构的结果,因此这不是有效的解决方案。我将暂时搁置它,也许,如果我真的讨厌我的时间,我会回去尝试解决它。

S[n_]:=Module[{a,b,c,d},G=Floor@Sqrt@#&;a=G@n;b:=G[n-a^2];c:=G[n-a^2-b^2];d:=G[n-a^2-b^2-c^2];While[Total[{a,b,c,d}^2]!=n,a-=1];{a,b,c,d}]

或者,不打扰:

S[n_] := Module[{a, b, c, d}, G = Floor@Sqrt@# &;
 a = G@n;
 b := G[n - a^2];
 c := G[n - a^2 - b^2];
 d := G[n - a^2 - b^2 - c^2];
 While[Total[{a, b, c, d}^2] != n, a -= 1];
 {a, b, c, d}
]

我对算法并不太看,但是我希望这是相同的想法。我只是想出了明显的解决方案,并对其进行了调整,直到它起作用为止。我测试了1到10亿之间的所有数字,并且...有效。该测试仅在我的计算机上花费约100秒。

这样做的好处是,由于b,c和d是使用延迟的分配定义的:=,因此当a减1时不必重新定义它们。这节省了我之前的几行内容。我可能会进一步打高尔夫球并嵌套多余的零件,但这是初稿。

哦,您可以按来运行它,S@123456789并且可以使用{S@#, Total[(S@#)^2]} & @ 123456789或对其进行测试# == Total[(S@#)^2]&[123456789]。详尽的测试是

n=0;
AbsoluteTiming@ParallelDo[If[e != Total[(S@e)^2], n=e; Abort[]] &, {e, 1, 1000000000}]
n

我以前使用过Print []语句,但这使它减慢了很多速度,即使它从未被调用过也是如此。去搞清楚。


这真的很干净!我感到惊讶的是,仅取每个值,只要取第一个尽可能大就足够了。对于打高尔夫球,将其另存n - a^2 - b^2 - c^2为变量并检查是否d^2等于变量可能要短一些。
xnor 2014年

2
真的有效吗?它为输入805306368找到了什么解决方案?
edc65

S [805306368] = {-28383,536 I,32 I,I}。嗯 这,当你总结它产生805306368,但是很显然在这个算法有问题。我想我现在必须撤消它。感谢您指出...
krs013

2
失败的所有数字似乎是由2大权力整除具体而言,它们似乎是这样的形式a * 4^(2^k)k>=2,具有提取出4所有权力,这样a不是4的倍数(但也可以是偶数)。而且,每个a都是3 mod 4,或者是这个数字的两倍。最小的是192
同或

1

Haskell 123 + 3 = 126

main=getLine>>=print.f.read
f n=head[map(floor.sqrt)[a,b,c,d]|a<-r,b<-r,c<-r,d<-r,a+b+c+d==n]where r=[x^2|x<-[0..n],n>=x^2]

预先计算的正方形上的简单蛮力。

它需要 -O编译选项(为此我添加了3个字符)。最坏的情况999950883需要不到1分钟的时间。

仅在GHC上测试。


1

C:198个字符

我可能会将其压缩到100个以上的字符。我喜欢这个解决方案的地方是最少的垃圾,只是一个普通的for循环,可以执行for循环应该做的事情(这很疯狂)。

i,a,b,c,d;main(n){for(scanf("%d",&n);a*a+b*b-n?a|!b?a*a>n|a<b?(--a,b=1):b?++b:++a:(a=b=0,--n,++i):c*c+d*d-i?c|!d?c*c>i|c<d?(--c,d=1):d?++d:++c:(a=b=c=d=0,--n,++i):0;);printf("%d %d %d %d",a,b,c,d);}

并美化了:

#include <stdio.h>

int n, i, a, b, c, d;

int main() {
    for (
        scanf("%d", &n);
        a*a + b*b - n
            ? a | !b
                ? a*a > n | a < b
                    ? (--a, b = 1)
                    : b
                        ? ++b
                        : ++a
                : (a = b = 0, --n, ++i)
            : c*c + d*d - i
                ? c | !d
                    ? c*c > i | c < d
                        ? (--c, d = 1)
                        : d
                            ? ++d
                            : ++c
                    : (a = b = c = d = 0, --n, ++i)
                : 0;
    );
    printf("%d %d %d %d\n", a, b, c, d);
    return 0;
}

编辑:对于所有输入来说,速度还不够快,但是我将返回另一个解决方案。到现在为止,我将让这个三元运算混乱。


1

版本B:C,179

a,b,c,d,m=1,n,q,r;main(){for(scanf("%d",&n);n%4<1;n/=4)m*=2;
for(a=sqrt(n),a-=(3+n-a*a)%4/2;r=n-a*a-b*b-c*c,d=sqrt(r),d*d-r;c=q%256)b=++q>>8;
printf("%d %d %d %d",a*m,b*m,c*m,d*m);}

感谢@Dennis的改进。下面的答案的其余部分未从版本A更新。

牧师A:C,195

a,b,c,d,n,m,q;double r=.1;main(){scanf("%d",&n);for(m=1;!(n%4);n/=4)m*=2;a=sqrt(n);a-=(3+n-a*a)%4/2;
for(;(d=r)-r;q++){b=q>>8;c=q%256;r=sqrt(n-a*a-b*b-c*c);}printf("%d %d %d %d ",a*m,b*m,c*m,d*m);}

比我的其他答案快得多,而且内存更少!

这使用http://en.wikipedia.org/wiki/Legendre%27s_three-square_theorem。下列形式以外的任何数字都可以表示为3平方和(我称其为禁止形式):

4^a*(8b+7), or equivalently 4^a*(8b-1)

请注意,所有奇数平方数均采用形式(8b+1),所有偶数平方数均以表面形式4b。但是,这掩盖了所有偶数均具有形式的事实4^a*(odd square)==4^a*(8b+1)。结果2^x-(any square number < 2^(x-1))x永远是禁止的形式。因此,这些数字及其倍数是困难的情况,这就是为什么很多程序在这里将4的幂除以第一步的原因。

如@xnor的回答所述,N-a*a对于2个连续的值,不能采用禁止的形式a。下面,我给出他的表格的简化形式。除以4除后N%4不能等于0 的事实外,请注意,仅有2个可能的值(a*a)%4

(a*a)%4= 01
        +--
       1|10
  N%4= 2|21  <- (N-a*a)%4
       3|32

因此,我们要避免(N-a*a)that的值可能是被禁止的形式,即(N-a*a)%43或0的值。可以看出N,对于奇数和偶数都不可能发生这种情况(a*a)

因此,我的算法如下所示:

1. Divide out powers of 4
2. Set a=int(sqrt(N)), the largest possible square
3. If (N-a*a)%4= 0 or 3, decrement a (only once)
4. Search for b and c such that N-a*a-b*b-c*c is a perfect square

我特别喜欢执行步骤3的方式。我将3加到N,因此,如果(3+N-a*a)%4 =3或2,则需要递减。(而不是1或0。)将其除以2,可以通过一个相当简单的表达式来完成整个工作。 。

非高尔夫代码

注单for回路q和利用区分/模数的推导的值b,并c从它。我尝试使用a除数而不是256来保存字节,但有时值a不合适,并且程序可能无限期挂起。256是最好的折衷,因为我可以用它>>8代替/256除法。

a,b,c,d,n,m,q;double r=.1;
main(){
  scanf("%d",&n);
  for(m=1;!(n%4);n/=4)m*=2;
  a=sqrt(n);
  a-=(3+n-a*a)%4/2;
  for(;(d=r)-r;q++){b=q>>8;c=q%256;r=sqrt(n-a*a-b*b-c*c);}
  printf("%d %d %d %d ",a*m,b*m,c*m,d*m);}

输出量

一个有趣的怪癖是,如果输入平方数,则N-(a*a)= 0。但是程序检测到0%4= 0并递减到下一个平方。结果,平方数输入总是分解成一组较小的平方,除非它们是形式4^x

999999999
31621 1 161 294

805306368
16384 0 16384 16384

999950883
31621 1 120 221

1
0 0 0 1

2
1 0 0 1

5
2 0 0 1

9
2 0 1 2

25
4 0 0 3

36
4 0 2 4

49
6 0 2 3

81
8 0 1 4

121
10 1 2 4

惊人!每次输入0.003 s!您可以取回这5个字符:1. m=1在之前声明main。2. scanffor语句中执行。3.使用float代替double。4. n%4<1比短!(n%4)。5. printf的格式字符串中有一个过时的空格。
丹尼斯


感谢您的提示!n-=a*a不起作用,因为a可以在以后进行修改(它给出了一些错误的答案,并在少数情况下(如100 + 7 = 107)挂起。)我将所有其余内容包括在内。缩短翻译printf长度可能会很好,但是我认为唯一的选择就是更改语言。速度的关键是要尽快确定好的价值a。用C编写并且搜索空间小于256 ^ 2,这可能是这里最快的程序。
级圣河

对,对不起 printf如果不使用宏或数组,则缩短该语句似乎很困难,否则会在其他位置增加体积。更改语言似乎是“简单”的方法。您的方法将在CJam中重82字节。
丹尼斯

0

JavaScript的- 175 191 176 173个字符

蛮力,但速度很快。

快速编辑,但是对于某些讨厌的输入来说还不够。我必须添加减少乘以4的第一步。

编辑2 摆脱功能,在循环内输出然后强制退出条件

编辑3 0不是有效的输入

v=(p=prompt)();for(m=1;!(v%4);m+=m)v/=4;for(a=-~(q=Math.sqrt)(v);a--;)for(w=v-a*a,b=-~q(w);b--;)for(x=w-b*b,c=-~q(x);c--;)(d=q(x-c*c))==~~d&&p([m*a, m*b, m*c, m*d],a=b=c='')

取消高尔夫:

v = prompt();

for (m = 1; ! (v % 4); m += m) 
{
  v /= 4;
}
for (a = - ~Math.sqrt(v); a--;) /* ~ force to negative integer, changing sign lead to original value + 1 */
{
  for ( w = v - a*a, b = - ~Math.sqrt(w); b--;)
  {
    for ( x = w - b*b, c = - ~Math.sqrt(x); c--;)
    {
      (d = Math.sqrt(x-c*c)) == ~~d && prompt([m*a, m*b, m*c, m*d], a=b=c='') /* 0s a,b,c to exit loop */
    }
  }
}

输出示例

123456789
11111,48,10,8

805306368
16384,16384,16384,0
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.