Mengapa menulis 1.000.000.000 sebagai 1000 * 1000 * 1000 dalam C?


142

Dalam kode yang dibuat oleh Apple, ada baris ini:

CMTimeMakeWithSeconds( newDurationSeconds, 1000*1000*1000 )

Apakah ada alasan untuk mengekspresikan 1,000,000,000sebagai 1000*1000*1000?

Kenapa tidak 1000^3?


45
Kejelasan dan keterbacaan kode. Anda tidak dapat menempatkan, atau 'sebagai pemisah dalam C, jadi hal terbaik berikutnya adalah menghitung nilai dari perkalian. ^ adalah operator yang tidak terkait dalam C - eksklusif ATAU.
Iwillnotexist Idonotexist

54
itu terutama digunakan untuk jangka waktu seperti: 2 * 60 * 60 .. mudah untuk melihat itu adalah untuk 2 jam ..
Idali

53
Untuk satu saya curiga 1.000.000.000 tidak sintaks yang valid
paparazzo

15
Omong-omong, bahasa pemrograman modern memiliki cara alternatif untuk menulis yang sama, misalnya dalam Swift 1_000_000_000. Namun, dengan konstanta waktu ini lebih sulit. Menulis lebih mudah dibaca 30 * 60(30 menit dalam detik) daripada menulis 1800. Sebenarnya ada bahasa yang akan memungkinkan Anda untuk menulis unit, misalnya meters, memungkinkan Anda untuk melindungi diri terhadap tugas yang buruk.
Sulthan

29
^adalah XOR, bukan eksponen atau operator daya.
3Dave

Jawaban:


200

Salah satu alasan untuk mendeklarasikan konstanta dengan cara multiplikatif adalah untuk meningkatkan keterbacaan, sementara kinerja run-time tidak terpengaruh. Juga, untuk menunjukkan bahwa penulis sedang berpikir secara berganda tentang nomor tersebut.

Pertimbangkan ini:

double memoryBytes = 1024 * 1024 * 1024;

Ini jelas lebih baik daripada:

double memoryBytes = 1073741824;

karena yang terakhir tidak terlihat, pada pandangan pertama, kekuatan ketiga 1024.

Seperti yang disebutkan Amin Negm-Awad, ^operatornya adalah biner XOR. Banyak bahasa tidak memiliki operator eksponensial built-in, waktu kompilasi, sehingga multiplikasi.


13
Dan dalam bahasa yang memiliki operator eksponensial, itu tidak selalu '^'. Di Fortran, misalnya, ini '**'.
jamesqf

4
Anda juga harus menyertakan tautan yang menunjuk ke peringatan penting, yang diberikan dalam jawaban di bawah ini, dari @chux: stackoverflow.com/a/40637622/1841533 (terutama karena OP menandai "c", yang sangat rentan terhadap 'tangan kanan' ini. operasi sisi tampaknya memiliki semua persyaratan terbatas pada tipe yang lebih kecil, dan karena itu perkaliannya mungkin melimpah 'masalah). securecoding.cert.org/confluence/display/c/… dapat membantu menghindari yang ada dalam kasus umum?
Olivier Dulac

4
Kita juga harus mencatat bahwa perhitungan dilakukan pada waktu kompilasi. Standar C mengharuskan implementasi untuk dapat menghitung ekspresi konstan pada waktu kompilasi untuk berbagai fitur bahasa dan kita dapat dengan aman menganggap itu benar ketika ekspresi konstan digunakan seperti dalam contoh ini.
ouah

13
Menyimpan jumlah memori dua kali lipat? Itu sepertinya sumber kesalahan potensial.
JAB

7
@supercat Saya sadar akan hal itu, tetapi dengan menggunakan double Anda dapat memiliki case di mana, katakanlah, Anda menginginkan sebagian dari rentang memori, Anda membaginya xuntuk mendapatkan ukuran subrange ... dan tiba-tiba Anda memiliki pecahan byte, yang mungkin memerlukan logika tambahan untuk menggantinya.
JAB

73

Mengapa tidak 1000^3?

Hasilnya 1000^3adalah 1003. ^adalah operator bit-XOR.

Meskipun tidak berurusan dengan Q itu sendiri, saya menambahkan klarifikasi. x^ytidak tidak selalu mengevaluasi x+yseperti dalam contoh penanya. Anda harus xor setiap bit. Dalam hal contoh:

1111101000 (1000₁₀)
0000000011 (3₁₀)
1111101011 (1003₁₀)

Tapi

1111101001 (1001₁₀)
0000000011 (3₁₀)
1111101010 (1002₁₀)

3
Pak, saya tidak jelas bagaimana 1003 ^ 3 adalah 1003. Google dan Mac Calculator menunjukkan 1000 ^ 3 = 1.000.000.000. dapatkah kamu menjelaskan
Mahesh

57
The ^berarti operator XOR di C / C ++ / Objective-C dll kalkulator biasanya berarti x-to-the-y listrik.
Tamás Zahola

5
Bah, bit 1000 dan 3 tidak tumpang tindih. Ini terlihat sangat salah.
Yakk - Adam Nevraumont

19
Bitnya tumpang tindih. Tapi bukan yang 1. : -]
Amin Negm-Awad

6
@ Yakk: memang, terlihat sangat salah! ... Saya berharap banyak orang tidak akan berpikir bahwa "A ^ B" selalu memberi A + B (tapi saya khawatir ada yang ...)
Olivier Dulac

71

Ada alasan untuk tidak menggunakannya 1000 * 1000 * 1000.

Dengan 16-bit int, 1000 * 1000meluap. Jadi menggunakan 1000 * 1000 * 1000mengurangi portabilitas.

Dengan 32-bit int, baris kode berikut berikut meluap.

long long Duration = 1000 * 1000 * 1000 * 1000;  // overflow
long long Duration = 1000000000000;  // no overflow, hard to read

Sarankan bahwa nilai timbal cocok dengan jenis tujuan untuk keterbacaan, portabilitas dan kebenaran.

double Duration = 1000.0 * 1000 * 1000;
long long Duration = 1000LL * 1000 * 1000 * 1000;

Juga dapat menggunakan enotasi sederhana untuk nilai-nilai yang secara tepat dapat direpresentasikan sebagai a double. Tentu saja hal ini mengarah pada mengetahui apakah doubledapat secara tepat merepresentasikan nilai angka keseluruhan - sesuatu yang berkaitan dengan nilai lebih besar dari 1e9. (Lihat DBL_EPSILONdan DBL_DIG).

long Duration = 1000000000;
// vs.
long Duration = 1e9;

5
Komentar yang sangat penting! securecoding.cert.org/confluence/display/c/… dapat membantu dalam banyak kasus?
Olivier Dulac

2
A doublepersis dapat mewakili semua bilangan bulat hingga 2 ^ 53 ≈ 9e15.
Edgar Bonet

3
@ EdgarBonet Benar bahwa binary64 dapat mewakili seluruh nomor hingga sekitar 9e15. Tetapi C tidak menentukan doublepenggunaan binary64, meskipun itu sangat umum digunakan. Per spec C, nilai hingga 1e9 atau lebih tepatnya dapat direpresentasikan. Itu tergantung jika Anda ingin kode untuk spec atau mengandalkan praktik umum.
chux - Reinstate Monica

4
@Patrick Kedua 1000dan 1000000000000yang bulat konstanta . Masing-masing secara independen memiliki jenis yang dipilih int, longatau long long. Kompiler menggunakan tipe pertama dari 3 yang cocok konstanta integer . 1000 * 1000 * 1000 * 1000dilakukan dengan intmatematika karena masing - masing 1000dalam int. Produk meluap dengan 32-bit int. 1000000000000 tentu direpresentasikan sebagai long long(atau mungkin lebih sempit) - tidak ada overflow. Jenis target long long Durationtidak mempengaruhi detemrinasi "sisi kanan =" ini.
chux - Reinstate Monica

2
Menempatkan tipe yang lebih luas terlebih dahulu dalam perkalian adalah penting. Dengan 16-bit int, long x = 1000 * 1000 * 1000L;akan meluap, sementara long x = 1000L * 1000 * 1000;tidak.
ex nihilo

51

Agar mudah dibaca.

Menempatkan koma dan spasi di antara nol ( 1 000 000 000atau 1,000,000,000) akan menghasilkan kesalahan sintaks, dan memiliki 1000000000dalam kode membuatnya sulit untuk melihat dengan tepat berapa banyak nol yang ada.

1000*1000*1000membuatnya jelas bahwa ini 10 ^ 9, karena mata kita dapat memproses potongan lebih mudah. Juga, tidak ada biaya runtime, karena kompiler akan menggantinya dengan konstanta 1000000000.


5
FYI, ada konsep digit separator yang saya pelajari baru-baru ini. Java sudah memilikinya untuk sementara waktu sekarang, dan C # 7.0 mungkin mendapatkannya. Saya berharap semua bahasa memiliki fitur eye-candy ini. :)
iheartcsharp

1
Bergantung pada konteks menggunakan 1,000,000,000tidak akan menghasilkan kesalahan sintaks, itu hanya akan berarti sesuatu yang lain. MisalnyaCMTimeMakeWithSeconds( newDurationSeconds, 1,000,000,000 )
Ross Ridge

2
@ JMS10 C # sudah memilikinya jika Anda menginstal versi pratinjau VS15, dapat ditulis sebagai1_000_000_000
user1306322

2
Python juga menjadi _pemisah :)
Wayne Werner

2
Dan C ++ baru-baru ini mendapat 'separator, di C ++ 14, jadi Anda bisa menggunakannya 1'000'000'000. (Itu dipilih karena 1,000,000,000dapat disalahartikan sebagai operator koma atau 4 parameter berbeda, dan _1_000_000_000merupakan nama variabel yang valid (tapi mungkin buruk).)
Justin Time - Reinstate Monica

27

Agar mudah dibaca. Sebagai perbandingan, Java mendukung _dalam jumlah untuk meningkatkan keterbacaan (pertama kali diusulkan oleh Stephen Colebourne sebagai balasan untuk PROPOSAL Derek Foster: Binary Literals untuk Project Coin / JSR 334). Orang akan menulis di 1_000_000_000sini.

Secara kronologis, mulai dari dukungan terlama hingga terbaru:

Ini adalah fitur yang relatif baru bagi bahasa untuk menyadari bahwa mereka harus mendukung (dan kemudian ada Perl). Seperti dalam jawaban yang sangat baik chux @, 1000*1000...adalah solusi parsial tetapi membuka programmer hingga bug dari meluap penggandaan bahkan jika hasil akhirnya adalah tipe besar.


Banyak bahasa pemrograman modern memiliki hal yang sama, misalnya Swift. Tidak ada yang baru.
Sulthan

AFAIK, ini berasal dari Perl. PL / M menggunakan $ untuk tujuan yang sama, misal: 0100 $ 0010B
ninjalj

1
Ini adalah cukup baru, meskipun. Fitur Java mungkin berusia 5 tahun. Sebagian besar bahasa lain yang mendukung sintaks ini cukup baru - Swift sendiri baru berusia beberapa tahun. Python menambahkan dukungan di 3.6, yang belum dirilis.
johncip

2
Ada telah mendukung garis bawah dalam integer literals selama 33 tahun sekarang.
Peter - Pasang kembali Monica

1
@djechlin: Saya telah diberi kebebasan untuk menambahkan lebih banyak informasi, secara kasar dalam urutan kronologis. Saya keliru sebelumnya, dilihat dari thread Project Coin, Stephen Colebourne mungkin mengambil ide menggarisbawahi dalam bilangan bulat integer dari Fandom dan / atau Ruby. Ruby mungkin mengambil ide dari Perl, dan Perl dari Ada.
ninjalj

7

Mungkin lebih mudah untuk membaca dan mendapatkan beberapa asosiasi dengan 1,000,000,000formulir.

Dari aspek teknis saya kira tidak ada perbedaan antara angka langsung atau perkalian. Kompilator akan menghasilkannya sebagai angka miliar konstan.

Jika Anda berbicara tentang objektif-c, maka 1000^3tidak akan berfungsi karena tidak ada sintaks untuk pow (itu adalah xor). Sebaliknya, pow()fungsi bisa digunakan. Tetapi dalam kasus itu, itu tidak akan optimal, itu akan menjadi panggilan fungsi runtime bukan kompiler yang dihasilkan konstan.


3

Untuk mengilustrasikan alasan pertimbangkan program uji berikut:

$ cat comma-expr.c && gcc -o comma-expr comma-expr.c && ./comma-expr
#include <stdio.h>

#define BILLION1 (1,000,000,000)
#define BILLION2 (1000^3)

int main()
{
        printf("%d, %d\n", BILLION1, BILLION2);
}
0, 1003
$

1
@ pjvandehaar Saya tidak akan merekomendasikan belajar bahasa dengan membaca artikel Wikipedia.
Peter - Reinstate Monica

0

Cara lain untuk mencapai efek yang sama dalam C untuk angka desimal adalah dengan menggunakan notasi floating point literal - asalkan dobel dapat mewakili angka yang Anda inginkan tanpa kehilangan presisi.

IEEE 754 64-bit double dapat mewakili integer non-negatif <= 2 ^ 53 tanpa masalah. Biasanya, panjang ganda (80 atau 128 bit) bisa lebih jauh dari itu. Konversi akan dilakukan pada waktu kompilasi, jadi tidak ada overhead runtime dan Anda mungkin akan mendapatkan peringatan jika ada kehilangan presisi yang tidak terduga dan Anda memiliki kompiler yang baik.

long lots_of_secs = 1e9;
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.