Kết quả bất ngờ khi làm việc với số nguyên rất lớn trên các ngôn ngữ được dịch


192

Tôi cố gắng để có được số tiền của 1 + 2 + ... + 1000000000, nhưng tôi nhận được kết quả hài hước trong PHP và Node.js .

PHP

$sum = 0;
for($i = 0; $i <= 1000000000 ; $i++) {
    $sum += $i;
}
printf("%s", number_format($sum, 0, "", ""));   // 500000000067108992

Node.js

var sum = 0;
for (i = 0; i <= 1000000000; i++) {
    sum += i ;
}
console.log(sum); // 500000000067109000

Câu trả lời đúng có thể được tính bằng

1 + 2 + ... + n = n(n+1)/2

Câu trả lời đúng = 500000000500000000 , vì vậy tôi quyết định thử một ngôn ngữ khác.

ĐI

var sum , i int64
for i = 0 ; i <= 1000000000; i++ {
    sum += i
}
fmt.Println(sum) // 500000000500000000

Nhưng nó hoạt động tốt! Vậy có gì sai với mã PHP và Node.js của tôi?

Có lẽ đây là vấn đề của các ngôn ngữ được giải thích và đó là lý do tại sao nó hoạt động trong một ngôn ngữ được biên dịch như Go? Nếu vậy, các ngôn ngữ được giải thích khác như Python và Perl có cùng một vấn đề không?


36
bạn cần điều này: php.net/manual/en/book.bc.php , nếu không bạn sẽ đánh đầu với IEEE 754 cho đến khi địa ngục đóng băng.
tereško

5
Để xử lý số lượng lớn trong PHP (tức là 64 bit), hãy sử dụng các hàm GMP, trong trường hợp này là gmp_add ().
Jeffrey

113
Để siêu hiệu quả, các vòng lặp của bạn nên thực sự bắt đầu từ 1 thay vì 0 .: P
Graham Borland

55
tổng (1 đến N) = (N / 2) * (N + 1)
Phong

5
@Baba 0 rất hữu ích cho tính toán của bạn, vì vậy không cần phải lặp lại thêm vòng lặp để thêm 0 thành 0.
Brian Warshaw

Câu trả lời:


155

Python hoạt động:

>>> sum(x for x in xrange(1000000000 + 1))
500000000500000000

Hoặc là:

>>> sum(xrange(1000000000+1))
500000000500000000

Tự intđộng của Python quảng bá cho Python longhỗ trợ độ chính xác tùy ý. Nó sẽ tạo ra câu trả lời đúng trên nền tảng 32 hoặc 64 bit.

Điều này có thể được nhìn thấy bằng cách tăng 2 lên một sức mạnh lớn hơn nhiều so với chiều rộng bit của nền tảng:

>>> 2**99
633825300114114700748351602688L

Bạn có thể chứng minh (với Python) rằng các giá trị sai lầm bạn nhận được trong PHP là do PHP đang quảng cáo nổi khi các giá trị lớn hơn 2 ** 32-1:

>>> int(sum(float(x) for x in xrange(1000000000+1)))
500000000067108992

Bạn đã chạy cái này trên hệ thống 32 hay 64 bit?
Baba

4
Nó nên hoạt động bất kể (32 so với 64 bit) vì Python ints tự động phát huy đến độ chính xác tùy ý thay vì tràn. Có thể mất một lúc lâu tho.
dawg

3
Python trên bất kỳ hệ thống nào cũng sẽ hoạt động trong trường hợp này, vì Python tự động chuyển sang số nguyên dài nếu cần. Và nếu điều đó là không đủ, nó cũng sẽ chuyển sang số nguyên lớn.
Alok Singhal

12
@ 0x499602D2: Điều đó thật khắc nghiệt. Chính OP đã bình chọn nó lên. Ông hỏi cụ thể đây có phải là vấn đề tương tự trên Python không. Trả lời, không, không phải vậy. Mã để cho thấy rằng nó không phải là. WTH?
dawg

10
Ví dụ Python quá dài, chỉ cần sử dụng sum (xrange (int (1e9) +1)) (.... sum hoạt động trên các iterables)
Jason Morgan

101

Mã Go của bạn sử dụng số học số nguyên với đủ bit để đưa ra câu trả lời chính xác. Không bao giờ chạm vào PHP hoặc Node.js, nhưng từ kết quả tôi nghi ngờ toán học được thực hiện bằng cách sử dụng các số dấu phẩy động và do đó được dự kiến ​​sẽ không chính xác cho các số có độ lớn này.


46
Vâng. If PHP encounters a number beyond the bounds of the integer type, it will be interpreted as a float instead. Also, an operation which results in a number beyond the bounds of the integer type will return a float instead.- php.net/manual/en/lingu.types.integer.php
Nate

3
Và trong NodeJS (và JavaScript nói chung), tất cả các phép toán số học (trừ các phép toán bit) hoạt động như thể chúng được thực hiện với các số dấu phẩy động. Cho dù chúng có thực sự là một sự phân biệt rõ ràng hay không tùy thuộc vào quyết định của từng công cụ JavaScript.
Peter Olson

13
Trong đặc tả của javascript, không có loại số nguyên. Tất cả các số là điểm nổi.
to nướng_flakes

8
@grasGendarme Có. Ví dụ, thông số ES5 chỉ định các chuyển đổi số nguyên khác nhau và bắt buộc chúng được gọi theo ca bit , chẳng hạn. Điều đó có nghĩa là đằng sau hậu trường , các loại số nguyên được sử dụng trong Javascript, nhưng tất cả các toán tử số học đều chuyển đổi toán hạng của chúng thành số dấu phẩy động trước khi làm bất cứ điều gì với chúng (tối ưu hóa trình biên dịch).
Peter Olson

2
Đây là mã tôi đoán nó đã bị rối vì tôi đã sử dụng float64 chứ không phải int64 .. Chỉ cần xác nhận nó không liên quan gì đến 32 hoặc 64 bit
Baba

45

Lý do là giá trị của biến số nguyên của bạn sumvượt quá giá trị tối đa. Và sumbạn nhận được là kết quả của số học dấu phẩy động bao gồm làm tròn số. Vì các câu trả lời khác không đề cập đến giới hạn chính xác, tôi quyết định đăng nó.

Giá trị số nguyên tối đa cho PHP cho:

  • Phiên bản 32 bit là 2147483647
  • Phiên bản 64 bit là 9223372036854775807

Vì vậy, điều đó có nghĩa là bạn đang sử dụng CPU 32 bit hoặc HĐH 32 bit hoặc phiên bản được biên dịch 32 bit của PHP. Nó có thể được tìm thấy bằng cách sử dụng PHP_INT_MAX. Điều sumnày sẽ được tính toán chính xác nếu bạn làm điều đó trên máy 64 bit.

Giá trị số nguyên tối đa trong JavaScript là 9007199254740992 . Giá trị tích phân chính xác lớn nhất bạn có thể làm việc là 2 53 (lấy từ câu hỏi này ). Việc sumvượt quá giới hạn này.

Nếu giá trị số nguyên không vượt quá các giới hạn này, thì bạn tốt. Nếu không, bạn sẽ phải tìm các thư viện số nguyên chính xác tùy ý.


28

Đây là câu trả lời trong C, cho đầy đủ:

#include <stdio.h>

int main(void)
{
    unsigned long long sum = 0, i;

    for (i = 0; i <= 1000000000; i++)    //one billion
        sum += i;

    printf("%llu\n", sum);  //500000000500000000

    return 0;
}

Chìa khóa trong trường hợp này là sử dụng kiểu dữ liệu của C99 long long . Nó cung cấp bộ lưu trữ nguyên thủy lớn nhất mà C có thể quản lý và nó chạy rất nhanh. Các long longloại cũng sẽ làm việc trên hầu hết bất kỳ máy 32 hoặc 64-bit.

Có một cảnh báo: các trình biên dịch được cung cấp bởi Microsoft rõ ràng không hỗ trợ tiêu chuẩn C99 14 tuổi, do đó, việc này để chạy trong Visual Studio là một điều tào lao.


3
MSVC ++ là trình biên dịch C ++ và C ++ có long longtrong tiêu chuẩn C ++ 11. Tuy nhiên, đây là một phần mở rộng MSVC ++ và g ++ trong một vài năm.
MSalters

1
@MSalters Vì vậy, là một tính năng C ++, nó sẽ không thực sự giúp bất kỳ ai biên dịch chương trình C thẳng. Tôi chưa bao giờ thử chuyển từ C sang C ++, vì vậy tôi không biết liệu cách giải quyết đó có thực sự hiệu quả hay không.
CyberSkull

19
Và độc đáo, GCC hoặc Clang với tối ưu hóa biến toàn bộ vòng lặp thànhmovabsq $500000000500000000, %rsi
Tor Klingberg

3
Chỉ gcc -O3hoặc clang -O3. Tôi không biết tên của tối ưu hóa cụ thể. Về cơ bản trình biên dịch thông báo rằng kết quả của vòng lặp không phụ thuộc vào bất kỳ đối số nào và tính toán nó tại thời gian biên dịch.
Tor Klingberg

1
C99 dài có kích thước tối thiểu 64 bit và theo như tôi biết là 64 bit trên cả nền tảng 32 bit và 64 bit. Tôi chưa thấy hỗ trợ chung cho ints quad hoặc octo.
Ngõ Devin

21

Tôi đoán là khi tổng vượt quá khả năng của một người bản địa int(2 31 -1 = 2.147.483.647), Node.js và PHP chuyển sang biểu diễn dấu phẩy động và bạn bắt đầu gặp lỗi làm tròn. Một ngôn ngữ như Go có thể sẽ cố gắng gắn bó với một dạng số nguyên (ví dụ: số nguyên 64 bit) càng lâu càng tốt (nếu, thực sự, nó đã không bắt đầu với điều đó). Vì câu trả lời khớp với số nguyên 64 bit, nên việc tính toán là chính xác.


Node.js rõ ràng không có kiểu int. Nó hoạt động theo kiểu phao.
greyfade

@greyfade - Vâng, tôi đoán điều đó đúng với tất cả các môi trường tuân thủ EcmaScript.
Ted Hopp

Có phải vậy không (2 ** 31 - 1)?
Zachary Hunter

@ZacharyHunter - Quả thực là như vậy. Cảm ơn đã bắt lỗi đó.
Ted Hopp

19

Kịch bản Perl cho chúng ta kết quả mong đợi:

use warnings;
use strict;

my $sum = 0;
for(my $i = 0; $i <= 1_000_000_000; $i++) {
    $sum += $i;
}
print $sum, "\n";  #<-- prints: 500000000500000000

3
Bạn đã chạy cái này trên hệ thống 32 hay 64 bit?
Baba

2
nó được thực hiện trên hệ thống 64 bit
Miguel Prz

3
4.99999999067109e+017trên Perl v5.16.1 MSWin32-x86.
Qtax

7
Nếu bạn thực sự cần số lớn, hãy sử dụng bignumhoặc bigint. Cả hai đều là các mô-đun cốt lõi, nghĩa là chúng được cài đặt với Perl v5.8.0 trở lên. Xem http://perldoc.perl.org/bignum.htmlhttp://perldoc.perl.org/bigint.html
Shawnhcorey

Tôi đã nhận được 500000000500000000 chạy cái này trên máy Mac PPC 32 bit, chạy Perl 5.12.4.
CyberSkull

17

Câu trả lời cho điều này là "đáng ngạc nhiên" đơn giản:

Đầu tiên - như hầu hết các bạn có thể biết - một 32-bit số nguyên dao động từ -2147483648 đến 2,147,483,647 . Vì vậy, điều gì xảy ra nếu PHP có kết quả, đó là LARGER hơn thế này?

Thông thường, người ta sẽ mong đợi một "Tràn" ngay lập tức, khiến 2.147.483.647 + 1 biến thành −2,147,483,648 . Tuy nhiên, đó không phải là trường hợp. NẾU PHP gặp một số lượng lớn hơn, nó trả về FLOAT thay vì INT.

Nếu PHP gặp một số nằm ngoài giới hạn của kiểu số nguyên, thì nó sẽ được hiểu là một số float thay thế. Ngoài ra, một hoạt động dẫn đến một số vượt quá giới hạn của loại số nguyên sẽ trả về một số float thay thế.

http://php.net/manual/en/lingu.types.integer.php

Điều này đã nói và biết rằng việc triển khai FLOAT của PHP đang tuân theo Định dạng chính xác kép của IEEE 754, có nghĩa là PHP có thể xử lý các con số lên tới 52 bit mà không mất độ chính xác. (Trên hệ thống 32 bit)

Vì vậy, tại Điểm, khi Sum của bạn đạt 9,007,199,254,740,992 (tức là 2 ^ 53 ) Giá trị Float được trả về bởi các Toán học PHP sẽ không còn đủ chính xác nữa.

E:\PHP>php -r "$x=bindec(\"100000000000000000000000000000000000000000000000000000\"); echo number_format($x,0);"

9,007,199,254,740,992

E:\PHP>php -r "$x=bindec(\"100000000000000000000000000000000000000000000000000001\"); echo number_format($x,0);"

9,007,199,254,740,992

E:\PHP>php -r "$x=bindec(\"100000000000000000000000000000000000000000000000000010\"); echo number_format($x,0);"

9,007,199,254,740,994

Ví dụ này cho thấy Điểm, trong đó PHP mất độ chính xác. Đầu tiên, bit có ý nghĩa cuối cùng sẽ bị loại bỏ, khiến 2 biểu thức đầu tiên dẫn đến một số bằng nhau - mà chúng không có.

Từ NGAY BÂY GIỜ, toàn bộ toán học sẽ sai, khi làm việc với các kiểu dữ liệu mặc định.

• Đây có phải là cùng một vấn đề đối với ngôn ngữ được giải thích khác như Python hoặc Perl không?

Tôi không nghĩ vậy. Tôi nghĩ rằng đây là vấn đề của các ngôn ngữ không có loại an toàn. Mặc dù tràn số nguyên như đã đề cập ở trên SILL xảy ra ở mọi ngôn ngữ sử dụng các loại dữ liệu cố định, các ngôn ngữ không có loại an toàn có thể cố gắng nắm bắt điều này với các kiểu dữ liệu khác. Tuy nhiên, một khi họ đạt được Biên giới "tự nhiên" (do hệ thống) - họ có thể trả lại bất cứ điều gì, nhưng kết quả đúng.

Tuy nhiên, mỗi ngôn ngữ có thể có các luồng khác nhau cho một Kịch bản như vậy.


15

Các câu trả lời khác đã giải thích những gì đang xảy ra ở đây (độ chính xác của dấu phẩy động như bình thường).

Một giải pháp là sử dụng một loại số nguyên đủ lớn hoặc hy vọng ngôn ngữ sẽ chọn một loại nếu cần.

Giải pháp khác là sử dụng thuật toán tổng hợp biết về vấn đề chính xác và làm việc xung quanh nó. Dưới đây bạn tìm thấy tổng kết tương tự, đầu tiên với số nguyên 64 bit, sau đó với dấu phẩy động 64 bit và sau đó sử dụng dấu phẩy động một lần nữa, nhưng với thuật toán tổng hợp Kahan .

Viết bằng C #, nhưng các ngôn ngữ khác cũng vậy.

long sum1 = 0;
for (int i = 0; i <= 1000000000; i++)
{
    sum1 += i ;
}
Console.WriteLine(sum1.ToString("N0"));
// 500.000.000.500.000.000

double sum2 = 0;
for (int i = 0; i <= 1000000000; i++)
{
    sum2 += i ;
}
Console.WriteLine(sum2.ToString("N0"));
// 500.000.000.067.109.000

double sum3 = 0;
double error = 0;
for (int i = 0; i <= 1000000000; i++)
{
    double corrected = i - error;
    double temp = sum3 + corrected;
    error = (temp - sum3) - corrected;
    sum3 = temp;
}
Console.WriteLine(sum3.ToString("N0"));
//500.000.000.500.000.000

Tổng kết Kahan cho một kết quả đẹp. Tất nhiên là mất nhiều thời gian hơn để tính toán. Việc bạn có muốn sử dụng hay không phụ thuộc vào a) vào hiệu suất của bạn so với nhu cầu chính xác và b) cách ngôn ngữ của bạn xử lý số nguyên so với kiểu dữ liệu dấu phẩy động.


@Baba Nó giống như với Node.js / JavaScript trong OP. Vì sao 500000000067109000 so với 500000000067108992 không có ý tưởng.
linac

Có lẽ Baba bị hấp dẫn bởi việc sử dụng dấu chấm cho hàng nghìn dấu phân cách: tiếng Anh thường mong đợi dấu phẩy. Bạn cũng có thể sử dụng dấu gạch dưới như một trung bình trung tính hơn.
didierc

14

Nếu bạn có PHP 32 bit, bạn có thể tính toán nó với bc :

<?php

$value = 1000000000;
echo bcdiv( bcmul( $value, $value + 1 ), 2 );
//500000000500000000

Trong Javascript, bạn phải sử dụng thư viện số tùy ý, ví dụ BigInteger :

var value = new BigInteger(1000000000);
console.log( value.multiply(value.add(1)).divide(2).toString());
//500000000500000000

Ngay cả với các ngôn ngữ như Go và Java, cuối cùng bạn sẽ phải sử dụng thư viện số tùy ý, số của bạn chỉ đủ nhỏ cho 64 bit nhưng quá cao cho 32 bit.


12

Trong Ruby:

sum = 0
1.upto(1000000000).each{|i|
  sum += i
}
puts sum

In 500000000500000000, nhưng mất 4 phút trên Intel i7 2,6 GHz của tôi.


Magnuss và Jaunty có giải pháp Ruby nhiều hơn:

1.upto(1000000000).inject(:+)

Để chạy điểm chuẩn:

$ time ruby -e "puts 1.upto(1000000000).inject(:+)"
ruby -e "1.upto(1000000000).inject(:+)"  128.75s user 0.07s system 99% cpu 2:08.84 total

10
1.upto (1000000000) .inject (: +)
Magnuss

@Magnuss: Đó là những gì tôi nghĩ lúc đầu tôi đã thử, nhưng nó đã gây ra rò rỉ bộ nhớ lớn. Bạn dường như làm việc ...
cgenco

11

Tôi sử dụng nút-bigint cho công cụ số nguyên lớn:
https://github.com/substack/node-bigint

var bigint = require('bigint');
var sum = bigint(0);
for(var i = 0; i <= 1000000000; i++) { 
  sum = sum.add(i); 
}
console.log(sum);

Nó không nhanh như thứ gì đó có thể sử dụng công cụ 64 bit gốc cho thử nghiệm chính xác này, nhưng nếu bạn có số lượng lớn hơn 64 bit, thì nó sử dụng libgmp dưới mui xe, đây là một trong những thư viện chính xác tùy ý nhanh hơn ngoài kia.


4

mất nhiều thời gian trong ruby, nhưng đưa ra câu trả lời đúng:

(1..1000000000).reduce(:+)
 => 500000000500000000 

4

Để có kết quả chính xác trong php Tôi nghĩ rằng bạn cần sử dụng các toán tử BC: http://php.net/manual/en/ref.bc.php

Đây là câu trả lời đúng trong Scala. Bạn phải sử dụng Long nếu không bạn sẽ tràn số:

println((1L to 1000000000L).reduce(_ + _)) // prints 500000000500000000

3

Thực sự có một mẹo hay cho vấn đề này.

Giả sử nó là 1-100 thay vào đó.

1 + 2 + 3 + 4 + ... + 50 +

100 + 99 + 98 + 97 + ... + 51

= (101 + 101 + 101 + 101 + ... + 101) = 101 * 50

Công thức:

Với N = 100: Đầu ra = N / 2 * (N + 1)

Với N = 1e9: Đầu ra = N / 2 * (N + 1)

Điều này nhanh hơn nhiều so với việc lặp qua tất cả các dữ liệu đó. Bộ xử lý của bạn sẽ cảm ơn bạn cho nó. Và đây là một câu chuyện thú vị liên quan đến chính vấn đề này:

http://www.jimloy.com/acheebra/gauss.htm


11
Bạn có nghĩ rằng có thể đi bộ qua mọi cây cầu qua Pregel ở Kaliningrad, mà không cần đi qua bất kỳ cây cầu nào hai lần không? Nhiều người đã thử và thất bại, nhưng chưa ai xác định rằng điều đó là không thể. Đây có vẻ như là một thách thức mà bạn sẽ có đủ điều kiện để giải quyết.
jwg

3

Điều này cho kết quả đúng trong PHP bằng cách buộc ép kiểu số nguyên.

$sum = (int) $sum + $i;

3

Lisp thông thường là một trong những ngôn ngữ * được giải thích nhanh nhất và xử lý các số nguyên lớn tùy ý theo mặc định. Quá trình này mất khoảng 3 giây với SBCL :

* (time (let ((sum 0)) (loop :for x :from 1 :to 1000000000 :do (incf sum x)) sum))

Evaluation took:
  3.068 seconds of real time
  3.064000 seconds of total run time (3.044000 user, 0.020000 system)
  99.87% CPU
  8,572,036,182 processor cycles
  0 bytes consed

500000000500000000
  • Theo cách hiểu, ý tôi là, tôi đã chạy mã này từ REPL, SBCL có thể đã thực hiện một số JITing trong nội bộ để làm cho nó chạy nhanh, nhưng trải nghiệm động khi chạy mã ngay lập tức là như nhau.

Có thể được đơn giản hóa dưới dạng (thời gian (vòng lặp cho x từ 1 đến 1000000000 tổng x)). Tôi đã đạt được tốc độ ~ 5x bằng cách thêm khai báo: (thời gian (cục bộ (khai báo (tối ưu hóa (tốc độ 3) (an toàn 0))) (vòng lặp cho i loại sửa lỗi từ 1 đến 1000000000 tổng i loại sửa lỗi))
huaiyuan

Điều này là sai lầm. Đừng để bạn bị mù bởi các ngôn ngữ khác! Cách chính xác để viết nó trong lisp là: (defun sum-from-1-to-n (n) (/ (* n (1+ n)) 2)) (time (sum-from-1-to-n 1000000000)) mất 14 micro giây (0,000014 giây) để chạy. Trong thời gian đó, và với 4 lõi CPU có sẵn, 0 micro (0,000000 giây) đã được chi tiêu trong chế độ người dùng 0 micro (0,000000 giây) đã được chi tiêu trong chế độ hệ thống -> 500000000500000000
informatimago

@informatimago: Không sai. Tôi đã sao chép kiểu vòng lặp bắt buộc của câu hỏi và như nhiều người đã chỉ ra, bản thân câu hỏi đề cập đến có một cách dễ dàng hơn để tính toán. Ớt.
postfuturist

3

Tôi không đủ uy tín để nhận xét về câu trả lời chung Lisp của @ postfuturist, nhưng nó có thể được tối ưu hóa để hoàn thành trong ~ 500ms với SBCL 1.1.8 trên máy của tôi:

CL-USER> (compile nil '(lambda () 
                        (declare (optimize (speed 3) (space 0) (safety 0) (debug 0) (compilation-speed 0))) 
                        (let ((sum 0))
                          (declare (type fixnum sum))
                          (loop for i from 1 to 1000000000 do (incf sum i))
                          sum)))
#<FUNCTION (LAMBDA ()) {1004B93CCB}>
NIL
NIL
CL-USER> (time (funcall *))
Evaluation took:
  0.531 seconds of real time
  0.531250 seconds of total run time (0.531250 user, 0.000000 system)
  100.00% CPU
  1,912,655,483 processor cycles
  0 bytes consed

500000000500000000

3

Vợt v 5.3.4 (MBP; thời gian tính bằng ms):

> (time (for/sum ([x (in-range 1000000001)]) x))
cpu time: 2943 real time: 2954 gc time: 0
500000000500000000

1
Đã xóa câu trả lời của tôi được đăng 6 phút sau bạn, một khi tôi nhận thấy câu trả lời của bạn. :)
Greg Hendershott

3

Hoạt động tốt trong Rebol:

>> sum: 0
== 0

>> repeat i 1000000000 [sum: sum + i]
== 500000000500000000

>> type? sum
== integer!

Điều này đã sử dụng Rebol 3, mặc dù được biên dịch 32 bit nhưng nó sử dụng số nguyên 64 bit (không giống như Rebol 2 sử dụng số nguyên 32 bit)


3

Tôi muốn xem những gì đã xảy ra trong CF Script

<cfscript>
ttl = 0;

for (i=0;i LTE 1000000000 ;i=i+1) {
    ttl += i;
}
writeDump(ttl);
abort;
</cfscript>

Tôi đã nhận được 5,0000000067E + 017

Đây là một thí nghiệm khá gọn gàng. Tôi khá chắc chắn rằng tôi có thể đã mã hóa điều này tốt hơn một chút với nhiều nỗ lực hơn.


3

ActivePerl v5.10.1 trên các cửa sổ 32 bit, intel core2duo 2.6:

$sum = 0;
for ($i = 0; $i <= 1000000000 ; $i++) {
  $sum += $i;
}
print $sum."\n";

kết quả: 5,0000000067109e + 017 trong 5 phút.

Với kịch bản "sử dụng bigint" đã hoạt động được hai giờ và sẽ hiệu quả hơn, nhưng tôi đã dừng nó. Quá chậm.


Bất cứ ai cũng có thể xác nhận rằng đó thực sự là việc thêm bao nhiêu thời gian lớn?
jwg

3

Để hoàn thiện, trong Clojure (đẹp nhưng không hiệu quả lắm):

(reduce + (take 1000000000 (iterate inc 1))) ; => 500000000500000000

1
Một chút hữu ích duy nhất mà các câu trả lời $ MY_FAVOURITE_LANGUAGE có là nếu chúng cung cấp kết quả ...
jwg

@jwg yeah xin lỗi tôi đã bỏ lỡ cuối dòng - câu trả lời cập nhật.
Blacksad

3

GIẢI THƯỞNG:

BEGIN { s = 0; for (i = 1; i <= 1000000000; i++) s += i; print s }

tạo ra kết quả sai tương tự như PHP:

500000000067108992

Có vẻ như AWK sử dụng dấu phẩy động khi các con số thực sự lớn, vì vậy ít nhất câu trả lời là thứ tự đúng.

Chạy thử:

$ awk 'BEGIN { s = 0; for (i = 1; i <= 100000000; i++) s += i; print s }'
5000000050000000
$ awk 'BEGIN { s = 0; for (i = 1; i <= 1000000000; i++) s += i; print s }'
500000000067108992

2

Danh mục ngôn ngữ khác:

Tcl:

Nếu sử dụng Tcl 8.4 trở lên thì tùy thuộc vào việc nó được biên dịch với 32 hay 64 bit. (8.4 là kết thúc cuộc đời).

Nếu sử dụng Tcl 8.5 hoặc mới hơn có số nguyên lớn tùy ý, nó sẽ hiển thị kết quả chính xác.

proc test limit {
    for {set i 0} {$i < $limit} {incr i} {
        incr result $i
    }
    return $result
}
test 1000000000 

Tôi đặt thử nghiệm bên trong một Proc để có được biên dịch byte.


2

Đối với mã PHP, câu trả lời là ở đây :

Kích thước của một số nguyên phụ thuộc vào nền tảng, mặc dù giá trị tối đa khoảng hai tỷ là giá trị thông thường (đó là 32 bit được ký). Các nền tảng 64 bit thường có giá trị tối đa khoảng 9E18. PHP không hỗ trợ số nguyên không dấu. Kích thước số nguyên có thể được xác định bằng cách sử dụng hằng số PHP_INT_SIZE và giá trị tối đa bằng cách sử dụng hằng số PHP_INT_MAX kể từ PHP 4.4.0 và PHP 5.0.5.


2

Hải cảng:

proc Main()

   local sum := 0, i

   for i := 0 to 1000000000
      sum += i
   next

   ? sum

   return

Kết quả trong 500000000500000000. (trên cả hai cửa sổ / mingw / x86 và osx / clang / x64)


2

Erlang hoạt động:

from_sum(From,Max) ->
    from_sum(From,Max,Max).
from_sum(From,Max,Sum) when From =:= Max ->
    Sum;
from_sum(From,Max,Sum) when From =/= Max -> 
    from_sum(From+1,Max,Sum+From).

Kết quả: 41> vô dụng: from_sum (1.1000000000). 500000000500000000


2

Điều thú vị là, PHP 5.5.1 cung cấp cho 499999999500000000 (trong khoảng 30 giây), trong khi đó, Dart2J cung cấp 500000000067109000 (điều này sẽ được mong đợi, vì đó là JS được thực thi). CLI Dart đưa ra câu trả lời đúng ... ngay lập tức.


2

Erlang cho kết quả mong đợi quá.

tổng hợp:

-module(sum).
-export([iter_sum/2]).

iter_sum(Begin, End) -> iter_sum(Begin,End,0).
iter_sum(Current, End, Sum) when Current > End -> Sum;
iter_sum(Current, End, Sum) -> iter_sum(Current+1,End,Sum+Current).

Và sử dụng nó:

1> c(sum).
{ok,sum}
2> sum:iter_sum(1,1000000000).
500000000500000000

2

Smalltalk:

(1 to: 1000000000) inject: 0 into: [:subTotal :next | subTotal + next ]. 

"500000000500000000"
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.