Hasil yang tidak terduga ketika bekerja dengan bilangan bulat yang sangat besar pada bahasa yang ditafsirkan

192

Saya mencoba untuk mendapatkan jumlah 1 + 2 + ... + 1000000000, tapi aku mendapatkan hasil yang lucu dalam PHP dan 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

Jawaban yang benar dapat dihitung dengan menggunakan

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

Jawaban yang benar = 500000000500000000 , jadi saya memutuskan untuk mencoba bahasa lain.

PERGILAH

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

Tapi itu bekerja dengan baik! Jadi apa yang salah dengan kode PHP dan Node.js saya?

Mungkin ini masalah bahasa yang ditafsirkan, dan itulah mengapa ia bekerja dalam bahasa yang dikompilasi seperti Go? Jika demikian, apakah bahasa yang ditafsirkan lain seperti Python dan Perl memiliki masalah yang sama?

Baba
sumber
36
Anda memerlukan ini: php.net/manual/en/book.bc.php , atau Anda akan memukul kepala Anda terhadap IEEE 754 sampai neraka membeku.
tereško
5
Untuk menangani jumlah besar di PHP (mis. 64-bit), gunakan fungsi GMP, dalam hal ini gmp_add ().
Jeffrey
113
Untuk efisiensi super, loop Anda harus benar-benar mulai dari 1 bukannya 0.: P
Graham Borland
55
jumlah (1 hingga N) = (N / 2) * (N + 1)
Phong
5
@Baba 0 superflous untuk perhitungan Anda, jadi tidak perlu memiliki iterasi tambahan dari loop untuk menambahkan 0 ke 0.
Brian Warshaw

Jawaban:

155

Python bekerja:

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

Atau:

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

Otomatis Python intmempromosikan ke Python longyang mendukung presisi sewenang-wenang. Ini akan menghasilkan jawaban yang benar pada platform 32 atau 64 bit.

Ini dapat dilihat dengan menaikkan 2 ke daya yang jauh lebih besar dari lebar bit platform:

>>> 2**99
633825300114114700748351602688L

Anda dapat mendemonstrasikan (dengan Python) bahwa nilai yang salah yang Anda peroleh di PHP adalah karena PHP mempromosikan ke float ketika nilainya lebih dari 2 ** 32-1:

>>> int(sum(float(x) for x in xrange(1000000000+1)))
500000000067108992
dawg
sumber
Apakah Anda menjalankan ini pada sistem 32 atau 64 bit?
Baba
4
Itu harus bekerja terlepas (32 vs 64 bit) karena Python ints otomatis mempromosikan ke presisi sewenang-wenang daripada meluap. Mungkin perlu waktu lebih lama.
dawg
3
Python pada sistem apa pun akan berfungsi dalam hal ini, karena Python beralih ke bilangan bulat panjang secara otomatis jika diperlukan. Dan jika itu tidak cukup, itu akan beralih ke bilangan bulat besar juga.
Alok Singhal
12
@ 0x499602D2: Itu agak kasar. OP sendiri memilihnya. Dia bertanya secara spesifik apakah ini masalah yang sama pada Python. Jawab, tidak bukan. Kode untuk menunjukkan bahwa itu bukan. WTH?
dawg
10
Contoh Python terlalu panjang, cukup gunakan sum (xrange (int (1e9) +1)) (.... sum bekerja di iterables)
Jason Morgan
101

Kode Go Anda menggunakan bilangan bulat aritmatika dengan bit yang cukup untuk memberikan jawaban yang tepat. Tidak pernah menyentuh PHP atau Node.js, tetapi dari hasil saya menduga matematika dilakukan menggunakan angka floating point dan dengan demikian diharapkan tidak tepat untuk angka sebesar ini.

zzzz
sumber
46
Ya. 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/language.types.integer.php
Nate
3
Dan di NodeJS (dan JavaScript pada umumnya) semua operasi aritmatika (kecuali operasi bit) berperilaku seolah-olah mereka dilakukan dengan angka floating point. Apakah mereka benar-benar ada atau tidak adalah perbedaan di bawah tenda untuk keputusan masing-masing mesin JavaScript.
Peter Olson
13
Dalam spesifikasi javascript, tidak ada tipe integer. Semua angka adalah floating point.
toasted_flakes
8
@grasGendarme Ada. ES5 spec menentukan berbagai konversi bilangan bulat dan mandat yang disebut dengan bitwise shift , misalnya. Artinya di balik layar , tipe integer digunakan dalam Javascript, tetapi semua operator aritmatika mengubah operan mereka menjadi angka floating point sebelum melakukan apa pun dengan mereka (pembatasan optimasi kompiler).
Peter Olson
2
di sini adalah kode saya kira itu kacau karena saya menggunakan float64 dan tidak int64 .. Hanya mengkonfirmasi itu tidak ada hubungannya dengan 32 atau 64 bit
Baba
45

Alasannya adalah bahwa nilai variabel integer Anda summelebihi nilai maksimum. Dan yang sumAnda dapatkan adalah hasil dari aritmatika float-point yang melibatkan pembulatan. Karena jawaban lain tidak menyebutkan batas pasti, saya memutuskan untuk mempostingnya.

Nilai integer maks untuk PHP untuk:

  • Versi 32-bit adalah 2147483647
  • Versi 64-bit adalah 9223372036854775807

Jadi itu berarti Anda menggunakan CPU 32 bit atau 32 bit OS atau versi 32 bit PHP yang dikompilasi. Itu dapat ditemukan menggunakan PHP_INT_MAX. The sumakan dihitung dengan benar jika Anda melakukannya pada mesin 64 bit.

Nilai integer maks dalam JavaScript adalah 9007199254740992 . Nilai integral persis terbesar yang dapat Anda gunakan adalah 2 53 (diambil dari pertanyaan ini ). Itusum melebihi batas ini.

Jika nilai integer tidak melebihi batas ini, maka Anda baik. Kalau tidak, Anda harus mencari perpustakaan integer presisi sewenang-wenang.

user568109
sumber
28

Inilah jawaban dalam C, untuk kelengkapan:

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

Kunci dalam hal ini adalah menggunakan tipe data C99 long long . Ini memberikan penyimpanan primitif terbesar yang dapat dikelola C dan beroperasi dengan sangat, sangat cepat. Itulong long jenis juga akan bekerja pada hampir semua mesin 32 atau 64-bit.

Ada satu peringatan: kompiler yang disediakan oleh Microsoft secara eksplisit tidak mendukung standar C99 yang berusia 14 tahun, sehingga menjalankan ini di Visual Studio adalah omong kosong.

CyberSkull
sumber
3
MSVC ++ adalah kompiler C ++, dan C ++ masuk long longdalam standar C ++ 11. Sudah merupakan ekstensi MSVC ++ dan g ++ selama beberapa tahun.
MSalters
1
@MSalters Jadi sebagai fitur C ++ tidak akan membantu siapa pun yang mengkompilasi program C langsung. Saya tidak pernah mencoba beralih dari C ke C ++, jadi saya tidak tahu apakah solusi itu benar-benar berfungsi.
CyberSkull
19
Dan bagusnya, GCC atau Dentang dengan optimasi mengubah seluruh loop menjadimovabsq $500000000500000000, %rsi
Tor Klingberg
3
Hanya gcc -O3atau clang -O3. Saya tidak tahu nama pengoptimalan spesifik. Pada dasarnya kompiler memperhatikan bahwa hasil dari loop tidak bergantung pada argumen apa pun, dan menghitungnya pada waktu kompilasi.
Tor Klingberg
1
Panjang panjang C99 memiliki ukuran minimum 64 bit dan sejauh yang saya tahu adalah 64 bit pada platform 32-bit dan 64-bit. Saya belum melihat dukungan umum untuk quad atau octo int.
Devin Lane
21

Dugaan saya adalah bahwa ketika jumlah melebihi kapasitas asli int(2 31 -1 = 2.147.483.647), Node.js dan PHP beralih ke representasi titik mengambang dan Anda mulai mendapatkan kesalahan pembulatan. Bahasa seperti Go mungkin akan mencoba bertahan dengan bentuk integer (mis., Integer 64-bit) selama mungkin (jika, memang, itu tidak dimulai dengan itu). Karena jawabannya cocok dengan integer 64-bit, perhitungannya tepat.

Ted Hopp
sumber
Node.js secara eksplisit tidak memiliki tipe int. Ini bekerja dalam tipe float.
greyfade
@greyfade - Ya, saya kira itu berlaku untuk semua lingkungan yang mendukung EcmaScript.
Ted Hopp
Bukan begitu (2 ** 31 - 1)?
Zachary Hunter
@ ZacharyHunter - Memang benar. Terima kasih telah menangkap kesalahan itu.
Ted Hopp
19

Script Perl memberi kami hasil yang diharapkan:

use warnings;
use strict;

my $sum = 0;
for(my $i = 0; $i <= 1_000_000_000; $i++) {
    $sum += $i;
}
print $sum, "\n";  #<-- prints: 500000000500000000
Miguel Prz
sumber
3
Apakah Anda menjalankan ini pada sistem 32 atau 64 bit?
Baba
2
dieksekusi pada sistem 64 bit
Miguel Prz
3
4.99999999067109e+017pada Perl v5.16.1 MSWin32-x86.
Qtax
7
Jika Anda benar-benar membutuhkan angka besar, gunakan bignumatau bigint. Keduanya adalah modul inti, yaitu, mereka menginstal dengan Perl v5.8.0 atau lebih tinggi. Lihat http://perldoc.perl.org/bignum.htmldanhttp://perldoc.perl.org/bigint.html
shawnhcorey
Saya mendapat 500000000500000000 menjalankan ini pada PPC Mac 32-bit, menjalankan Perl 5.12.4.
CyberSkull
17

Jawaban untuk ini "secara mengejutkan" sederhana:

Pertama - karena sebagian besar dari Anda mungkin tahu - bilangan bulat 32-bit berkisar dari 2.147.483.648 hingga 2.147.483.647 . Jadi, apa yang terjadi jika PHP mendapatkan hasil, yang LEBIH BESAR dari ini?

Biasanya, orang akan mengharapkan "Overflow" langsung, menyebabkan 2.147.483.647 +1 berubah menjadi −2.147.483.648 . Namun, itu BUKAN terjadi. JIKA PHP menemukan jumlah yang lebih besar, itu Mengembalikan FLOAT daripada INT.

Jika PHP menemukan angka di luar batas tipe integer, itu akan ditafsirkan sebagai float. Juga, operasi yang menghasilkan angka di luar batas tipe integer akan mengembalikan float sebagai gantinya.

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

Ini mengatakan, dan mengetahui bahwa implementasi PHP FLOAT mengikuti Format presisi ganda IEEE 754, berarti, PHP mampu menangani angka hingga 52 bit, tanpa kehilangan presisi. (Pada Sistem 32-bit)

Jadi, di Point, di mana jumlah Anda mencapai 9.007.199.254.740.992 (yang merupakan 2 ^ 53 ) Nilai Float yang dikembalikan oleh PHP Maths tidak lagi cukup akurat.

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

Contoh ini Shows the Point, di mana PHP kehilangan presisi. Pertama, bit signifikansi terakhir akan dihapus, menyebabkan 2 ekspresi pertama menghasilkan angka yang sama - yang tidak.

Mulai SEKARANG, seluruh matematika akan salah, saat bekerja dengan tipe data default.

• Apakah itu masalah yang sama untuk bahasa yang ditafsirkan lain seperti Python atau Perl?

Saya kira tidak. Saya pikir ini adalah masalah bahasa yang tidak memiliki keamanan jenis. Sementara Integer Overflow seperti yang disebutkan di atas AKAN terjadi di setiap bahasa yang menggunakan tipe data tetap, bahasa tanpa keamanan tipe mungkin mencoba untuk menangkap ini dengan tipe data lain. Namun, begitu mereka mencapai Perbatasan "alami" (yang diberikan Sistem) - mereka mungkin mengembalikan apa pun, tetapi hasilnya benar.

Namun, setiap bahasa dapat memiliki utas berbeda untuk Skenario semacam itu.

dognose
sumber
15

Jawaban lain sudah menjelaskan apa yang terjadi di sini (presisi floating point seperti biasa).

Salah satu solusinya adalah menggunakan tipe integer yang cukup besar, atau berharap bahasa akan memilih satu jika diperlukan.

Solusi lain adalah dengan menggunakan algoritma penjumlahan yang tahu tentang masalah presisi dan bekerja di sekitarnya. Di bawah ini Anda menemukan penjumlahan yang sama, pertama dengan integer 64 bit, kemudian dengan floating point 64 bit dan kemudian menggunakan floating point lagi, tetapi dengan algoritma penjumlahan Kahan .

Ditulis dalam C #, tetapi hal yang sama berlaku untuk bahasa lain juga.

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

Penjumlahan Kahan memberikan hasil yang indah. Tentu saja butuh waktu lebih lama untuk dihitung. Apakah Anda ingin menggunakannya tergantung a) pada kinerja Anda vs kebutuhan presisi, dan b) bagaimana bahasa Anda menangani tipe data integer vs floating point.

linac
sumber
@Baba Sama dengan Node.js / JavaScript di OP. Seperti mengapa 500000000067109000 vs 500000000067108992 ... tidak tahu.
linac
Mungkin Baba tertarik dengan penggunaan titik-titik untuk ribuan pemisah: bahasa Inggris biasanya mengharapkan koma. Anda juga bisa menggunakan garis bawah sebagai cara yang lebih netral.
didierc
14

Jika Anda memiliki PHP 32-Bit, Anda dapat menghitungnya dengan bc :

<?php

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

Dalam Javascript Anda harus menggunakan pustaka angka arbitrer, misalnya BigInteger :

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

Bahkan dengan bahasa seperti Go dan Java Anda akhirnya harus menggunakan pustaka angka arbitrer, nomor Anda kebetulan cukup kecil untuk 64-bit tetapi terlalu tinggi untuk 32-bit.

Esailija
sumber
12

Di Ruby:

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

Mencetak 500000000500000000, tetapi membutuhkan 4 menit dengan baik pada Intel i7 2,6 GHz.


Magnuss dan Jaunty memiliki lebih banyak solusi Ruby:

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

Untuk menjalankan tolok ukur:

$ 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
cgenco
sumber
10
1.upto (1000000000) .inject (: +)
Magnuss
@ Maguss: Itulah yang saya pikir saya coba pada awalnya, tetapi menyebabkan kebocoran memori yang sangat besar. Tampaknya pekerjaan Anda ...
cgenco
11

Saya menggunakan simpul-bigint untuk hal-hal integer besar:
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);

Ini tidak secepat sesuatu yang dapat menggunakan hal-hal 64-bit asli untuk pengujian yang tepat ini, tetapi jika Anda masuk ke angka yang lebih besar dari 64-bit, ia menggunakan libgmp di bawah tenda, yang merupakan salah satu perpustakaan presisi cepat yang berubah-ubah di luar sana.

Eve Freeman
sumber
4

butuh waktu lama di ruby, tetapi memberikan jawaban yang benar:

(1..1000000000).reduce(:+)
 => 500000000500000000 
Jauny
sumber
4

Untuk mendapatkan hasil yang benar dalam php saya pikir Anda harus menggunakan operator matematika BC: http://php.net/manual/en/ref.bc.php

Inilah jawaban yang benar di Scala. Anda harus menggunakan Longs jika tidak, Anda melimpah nomornya:

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

Sebenarnya ada trik keren untuk masalah ini.

Asumsikan itu 1-100 sebagai gantinya.

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

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

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

Rumus:

Untuk N = 100: Output = N / 2 * (N + 1)

Untuk N = 1e9: Output = N / 2 * (N + 1)

Ini jauh lebih cepat daripada perulangan melalui semua data itu. Prosesor Anda akan berterima kasih untuk itu. Dan di sini ada cerita menarik tentang masalah ini:

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

pengguna2522001
sumber
11
Apakah Anda pikir mungkin untuk berjalan di setiap jembatan di seberang Pregel di Kaliningrad, tanpa melintasi jembatan dua kali? Banyak orang telah mencoba dan gagal, tetapi belum ada yang menetapkan bahwa itu tidak mungkin. Ini sepertinya tantangan yang harus Anda pecahkan secara unik.
jwg
3

Ini memberikan hasil yang tepat dalam PHP dengan memaksa cast integer.

$sum = (int) $sum + $i;
ck_
sumber
3

Common Lisp adalah salah satu bahasa * yang ditafsirkan tercepat dan menangani bilangan bulat besar yang sewenang-wenang secara default. Ini membutuhkan waktu sekitar 3 detik dengan 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
  • Dengan mengartikan, maksud saya, saya menjalankan kode ini dari REPL, SBCL mungkin telah melakukan JITing secara internal untuk membuatnya berjalan cepat, tetapi pengalaman dinamis menjalankan kode segera sama.
postfuturist
sumber
Dapat disederhanakan sebagai (waktu (loop untuk x dari 1 hingga 10.000.000 jumlah x)). Saya mendapat ~ 5x kecepatan dengan menambahkan deklarasi: (waktu (secara lokal (nyatakan (optimalkan (kecepatan 3)) (keselamatan 0))) (loop untuk fixnum bertipe 1 dari 1000000000 jumlah saya fixnum bertipe)))
huaiyuan
Ini salah. Jangan sampai Anda dibutakan oleh bahasa lain! Cara yang benar untuk menuliskannya dalam lisp adalah: (defun sum-from-1-to-n (n) (/ (* n (1+ n)) 2)) (waktu (jumlah-dari-1-ke-n 1000000000)) membutuhkan 14 mikrodetik (0,000014 detik) untuk dijalankan. Selama periode itu, dan dengan 4 core CPU yang tersedia, 0 mikrodetik (0,000000 detik) dihabiskan dalam mode pengguna 0 mikrodetik (0,000000 detik) dihabiskan dalam mode sistem -> 50000000050000000000
informatimago
@informatimago: Ini tidak salah. Saya menyalin gaya loop imperatif dari pertanyaan dan seperti yang telah banyak ditunjukkan, pertanyaan itu sendiri menyebutkan ada cara yang lebih mudah untuk menghitung. Chillax.
postfuturist
3

Saya tidak memiliki reputasi yang cukup untuk mengomentari jawaban Common Lisp @ postfuturist, tetapi dapat dioptimalkan untuk diselesaikan dalam ~ 500ms dengan SBCL 1.1.8 pada mesin saya:

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
jdtw
sumber
3

Racket v 5.3.4 (MBP; waktu dalam ms):

> (time (for/sum ([x (in-range 1000000001)]) x))
cpu time: 2943 real time: 2954 gc time: 0
500000000500000000
Keith Flower
sumber
1
Menghapus jawaban saya yang diposting 6 menit setelah Anda, setelah saya perhatikan jawaban Anda. :)
Greg Hendershott
3

Bekerja dengan baik di Rebol:

>> sum: 0
== 0

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

>> type? sum
== integer!

Ini menggunakan Rebol 3 yang walaupun dikompilasi 32 bit namun menggunakan integer 64-bit (tidak seperti Rebol 2 yang menggunakan integer 32 bit)

draegtun
sumber
3

Saya ingin melihat apa yang terjadi di CF Script

<cfscript>
ttl = 0;

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

Saya mendapat 5.00000000067E + 017

Ini adalah eksperimen yang cukup rapi. Saya cukup yakin saya bisa membuat kode ini sedikit lebih baik dengan lebih banyak usaha.

georgiamadkow
sumber
3

ActivePerl v5.10.1 pada windows 32bit, intel core2duo 2.6:

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

hasil: 5.00000000067109e + 017 dalam 5 menit.

Dengan skrip "gunakan bigint" bekerja selama dua jam, dan akan bekerja lebih banyak, tetapi saya menghentikannya. Terlalu lambat.

Licik
sumber
Adakah yang bisa memastikan bahwa itu benar-benar berapa lama menambahkan yang dibutuhkan banyak bigint?
jwg
3

Demi kelengkapan, di Clojure (cantik tapi tidak terlalu efisien):

(reduce + (take 1000000000 (iterate inc 1))) ; => 500000000500000000
Blacksad
sumber
1
Satu-satunya hal kecil yang berguna yang dimiliki jawaban $ MY_FAVOURITE Westph adalah jika mereka memberikan hasilnya ...
jwg
@ jwg ya maaf saya melewatkan akhir baris - jawaban yang diperbarui.
Blacksad
3

AWK:

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

menghasilkan hasil yang salah sama seperti PHP:

500000000067108992

Tampaknya AWK menggunakan floating point ketika angkanya benar-benar besar, jadi setidaknya jawabannya adalah urutan besarnya yang tepat.

Tes berjalan:

$ 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
QuasarDonkey
sumber
2

Kategori bahasa yang ditafsirkan lainnya:

Tcl:

Jika menggunakan Tcl 8.4 atau lebih tua itu tergantung apakah itu dikompilasi dengan 32 atau 64 bit. (8.4 adalah akhir kehidupan).

Jika menggunakan Tcl 8.5 atau lebih baru yang memiliki bilangan bulat besar sembarang, itu akan menampilkan hasil yang benar.

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

Saya meletakkan tes di dalam proc untuk mendapatkannya byte-compiled.

Johannes Kuhn
sumber
2

Untuk kode PHP, jawabannya ada di sini :

Ukuran integer tergantung pada platform, meskipun nilai maksimum sekitar dua miliar adalah nilai biasa (yang 32 bit ditandatangani). Platform 64-bit biasanya memiliki nilai maksimum sekitar 9E18. PHP tidak mendukung bilangan bulat yang tidak ditandatangani. Ukuran integer dapat ditentukan menggunakan PHP_INT_SIZE konstan, dan nilai maksimum menggunakan PHP_INT_MAX konstan sejak PHP 4.4.0 dan PHP 5.0.5.

vicentazo
sumber
2

Pelabuhan:

proc Main()

   local sum := 0, i

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

   ? sum

   return

Hasil dalam 500000000500000000. (pada kedua windows / mingw / x86 dan osx / clang / x64)

vszakats
sumber
2

Erlang bekerja:

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

Hasil: 41> tidak berguna: from_sum (1,1000000000). 500000000500000000

Steve Moon
sumber
2

Lucunya, PHP 5.5.1 memberi 49999999950000000000 (dalam ~ 30s), sedangkan Dart2Js memberi 500000000067109000 (yang diharapkan, karena JS-lah yang dieksekusi). CLI Dart memberikan jawaban yang tepat ... secara instan.

Doru Moisa
sumber
2

Erlang memberikan hasil yang diharapkan juga.

sum.erl:

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

Dan menggunakannya:

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

Smalltalk:

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

"500000000500000000"
Samuel Henry
sumber