Dalam bahasa yang tidak memungkinkan garis bawah dalam konstanta integer, apakah ini praktik yang baik untuk membuat konstanta untuk 1 miliar?

39

Dalam bahasa yang tidak memungkinkan garis bawah dalam bilangan bulat integer , apakah itu ide yang baik untuk membuat konstanta untuk 1 miliar? misalnya dalam C ++:

size_t ONE_BILLION = 1000000000;

Tentu saja, kita tidak boleh membuat konstanta untuk angka kecil seperti 100. Tetapi dengan 9 nol, bisa dibilang mudah untuk meninggalkan nol atau menambahkan satu lagi dalam kode seperti ini:

tv_sec = timeInNanosec / 1000000000;
tv_nsec = timeInNanosec % 1000000000;
Martin C. Martin
sumber
24
Saya harap semua orang di sini memilih TIDAK . Dengan begitu, mungkin suatu hari bank saya akan mentransfer satu miliar dolar ke akun saya karena seorang programmer tidak menggunakan konstanta dan salah meletakkan nol! :)
Reactgular
43
Mengapa tidak membuat konstanta untuk angka kecil? Apa yang dimaksud dengan 100? Kecuali ada beberapa konteks, itu adalah angka ajaib.
Allan
4
@MathewFoscarini Secara umum, kesalahan bisa terjadi. Tetapi ketika datang ke bank Anda, kesalahan akan selalu melawan Anda.
emory
23
Pertimbangkan menulis 1e9, 10^9atau 1_000_000_000jika bahasa yang Anda gunakan mendukungnya.
hammar
5
Skala panjang atau miliar skala pendek ?
nilai p

Jawaban:

33

Sebagian besar bahasa menampilkan semacam notasi eksponensial. Satu juta adalah 1e6, (artinya 1 kali 10 pangkat 6). Ini pada dasarnya memecahkan masalah lebih baik daripada kebanyakan proposisi di sini.

Dalam banyak bahasa mirip-C, notasi ilmiah mendefinisikan tipe floating point , yang sangat disayangkan jika Anda benar-benar membutuhkan int. Namun, Anda dapat dengan mudah mengetikkan konstanta itu untuk menghindari konversi tersirat di formular Anda.

n / int(1e9) akan membagi dengan satu miliar.

Dalam contoh Anda, berurusan dengan jumlah fisik (waktu dalam nanodetik), saya biasanya akan bertanya pada diri sendiri apakah bilangan bulat adalah tipe yang tepat. Bahkan titik mengambang doublemungkin lebih cocok ketika berhadapan dengan jumlah yang terukur (walaupun tentu saja ada kasus di mana Anda lebih suka a long long).

wirrbel
sumber
6
Saya pikir solusi NANOSECONDS_IN_ONE_SECOND jauh lebih jelas dan lebih rapi
Thomas Bonini
1
Pertanyaannya adalah tentang bilangan bulat liberal dan saya mengusulkan untuk menggunakan notasi ilmiah. Apakah untuk melakukan ini di tempat atau dengan mendefinisikan konstanta adalah masalah kode penataan yang tidak diminta dalam pertanyaan. Menentukan konstanta menambahkan abstraksi terbatas, saya akan menulis fungsi konversi / makro untuk mencapai abstraksi yang lebih baik
wirrbel
1
Akankah casting ganda yang sangat besar ke int tidak mengambil risiko masalah pembulatan perbedaan khas angka floating point?
Philipp
dengan tipe integer presisi normal ini seharusnya tidak menjadi masalah selama Anda menggunakan float presisi ganda untuk mengkonversi. Anda benar saat menggunakan nilai long longrentang.
wirrbel
145

Buat yang disebut NANOSECONDS_IN_ONE_SECOND sebagai gantinya.

Atau nama yang lebih pendek dan lebih baik jika Anda bisa memikirkannya.

JohnB
sumber
58
Saya akan mengatakan Nanoseconds_Per_Secondtetapi ini, menurut pendapat saya, jawaban yang benar.
KChaloux
8
@ Nyonya, saya tidak mengerti maksud Anda. Tidak ada yang salah dengan mengatakan milimeter per meter. Anda mungkin menyiratkan bahwa itu berlebihan, dalam nanosecond BERARTI satu miliar fraksi per detik, tetapi tidak ada yang salah dengan menyatakannya lagi. Ini seperti mengatakan 1 + 1 = 2. "x per y" terus lebih masuk akal ketika x dan y terpisah, seperti "unit per setengah lusin" atau "nanodetik per milidetik"
Mark Canlas
7
@MathewFoscarini Sebenarnya, tidak, dalam konteks ini tidak. Jika ya, konstanta bernama NANOSECONDStidak ada artinya karena Anda tidak bisa mengatakan apa yang seharusnya diterapkan. Demikian juga, NANOSECONDS_PER_MICROSECONDadalah konstanta valid serupa yang masuk akal.
Izkata
5
@MathewFoscarini, "milimeter per meter" adalah cara untuk menghapus unit pada konversi untuk mendapatkan nilai mentah. 1mm/1m = 1000, Yang merupakan persis titik apa yang sedang dilakukan di sini.
zzzzBov
11
Kenapa banyak mengetik? NS_PER_SECharus jelas bagi siapa saja yang seharusnya berurusan dengan nanodetik.
Rex Kerr
67

Konstanta dimaksudkan untuk memberi makna angka. Tidak ada arti tambahan ONE_BILLIONuntuk 1000000000. Sebenarnya, itu membuatnya lebih membingungkan, karena dalam bahasa alami yang berbeda, satu miliar berarti sesuatu yang berbeda (baik seribu juta atau sejuta juta)! Jika Anda ingin menulisnya lebih pendek, ada kemungkinan bahasa pemrograman Anda memungkinkan penggunaan notasi ilmiah, yaitu 1e9. Kalau tidak, saya setuju dengan @JohnB, bahwa angka ini benar-benar berarti jumlah nanodetik dalam sedetik, jadi sebutkan saja.

Thijs van Dien
sumber
9
Bagus menunjukkan bahwa miliar dalam berbagai bahasa berarti jumlah nol yang berbeda.
frozenkoi
3
menyarankan mengubah bahasa reguler ke bahasa alami. reguler berarti sesuatu yang lain ...
jk.
Penafsiran yang berbeda tentang "miliar" dalam bahasa merupakan poin yang bagus! Mengapa saya tidak bisa menjawab pertanyaan Anda dua kali!
DSF
3
Anda tidak perlu bahasa yang berbeda. Anda bahkan tidak memerlukan negara yang berbeda. Dalam bahasa Inggris Britania, "miliar" berarti sesuatu yang berbeda sebelum dan sesudah 1974 dalam komunikasi resmi (media massa dan pemerintah), dan kedua penggunaan masih ada.
Jörg W Mittag
1
" Tidak ada makna tambahan dalam ONE_BILLION hingga 10000000000 .. Saya tidak setuju. (Petunjuk: Saya sengaja salah mengutip Anda dan menambahkan angka nol; akankah memperhatikan jika saya tidak menyebutkannya?)
Keith Thompson
27

Untuk satu atau dua penggunaan, saya akan menggunakan konvensi:

tv_sec = timeInNanosec / (1000 * 1000 * 1000);
tv_nsec = timeInNanosec % (1000 * 1000 * 1000);

Ini sangat jelas, bisa dikompilasi menjadi konstan dan sulit untuk dikacaukan.

Juga, ini sangat berguna dalam kasus-kasus seperti:

var Time = 24 * 60 * 60;

di mana mudah untuk melihat kita berbicara tentang satu hari dalam hitungan detik.

Sklivvz
sumber
Inilah yang biasanya saya lakukan. Ini juga memiliki keuntungan bahwa saya tidak akan lupa bahwa saya mendefinisikan NANOSECONDS_IN_ONE_SECOND kemarin dan mendefinisikan NANOSECONDS_PER_SECOND hari ini. Dan mungkin ONE_AMERICAN_BILLION besok.
Thomas Padron-McCarthy
Tentunya 'SecondsInOneDay = 24 * 60 * 60' masih lebih mudah?
JBRWilkinson
@JBRWilkinson yakin, cuplikan awal saya menggunakan kelas instance.Time = ..., tapi kemudian saya membungkamnya ...
Sklivvz
3
Dalam C atau C ++, (1000 * 1000 * 1000)adalah tipe int, yang hanya diperlukan 16 bit, sehingga bisa meluap. Anda dapat menulis (1000L * 1000L * 1000L)untuk menghindarinya.
Keith Thompson
Saya sering melakukan ini. Ini bekerja dengan sangat baik.
vy32
10

Panjang nilainya bukan yang menentukan apakah konstanta diperlukan atau tidak.

Anda menggunakan konstanta untuk menghindari angka ajaib , bukan untuk menghindari mengetik.

Misalnya ini adalah konstanta yang benar-benar valid:

public static final int CLOSE_CURSORS_AT_COMMIT = 1;
public static final int CONCUR_READ_ONLY = 2;
public static final int CONCUR_UPDATABLE = 3;
public static final int FETCH_FORWARD = 4;
public static final int FETCH_REVERSE = 5; 
public static final int FETCH_UNKNOWN = 6;
public static final int HOLD_CURSORS_OVER_COMMIT = 7;
public static final int TYPE_FORWARD_ONLY = 8;
public static final int TYPE_SCROLL_INSENSITIVE = 9;
public static final int TYPE_SCROLL_SENSITIVE = 10;

Menggunakan:

public static final int NANOSECS_PER_SECOND = 1000000000;

(contoh kode di Jawa, terjemahkan ke bahasa favorit Anda)

Tulains Córdova
sumber
3
+1 Nomor yang disebutkan hampir tidak berguna. Tujuan dari konstanta itu untuk memberi makna pada angka-angka itu. Apa yang mereka wakili? Apa yang mereka hitung atau batasi atau yang secara resmi disebut koefisien? Tidak berapa nilai hitungannya.
JustinC
5
Melihat kita berbicara tentang Java, saya akan membuat pengamatan bahwa, pada Java 7, kita dapat memasukkan angka dalam jumlah untuk membantu keterbacaan!
Nick
2
Itu adalah contoh mengerikan dari konstanta yang valid. Mereka seharusnya enum, kecuali mereka diciptakan sebelum enum.
Christoffer Hammarström
@ ChristofferHammarström Mereka memang dibuat sebelum enum, mereka adalah bagian dari kelas ResultSet, dalam paket SQL Java SDK.
Tulains Córdova
2
@ ChristofferHammarström Mereka buruk karena sekarang kita memiliki enum tetapi bukan karena tidak berarti. Enum tidak ada ketika kelas-kelas ini dibuat dan untuk membedakan antara opsi yang saling eksklusif seperti FETCH_FORWARD dan FETCH_REVERSE memberi mereka nilai yang berbeda. Nilai tidak masalah, hanya fakta bahwa mereka berbeda.
Tulains Córdova
8

Miliaran orang Amerika atau Eropa?

(atau dalam istilah teknis, satu miliar dalam skala pendek atau panjang - satu adalah 1.000 juta, yang lain adalah satu juta juta).

Mengingat kebingungan ini, maka saya akan mengatakan ya - masuk akal untuk mendefinisikannya sekali dan tetap menggunakannya, demikian juga berlaku untuk konstanta yang Anda perlukan untuk menyetujui definisi tentang - mendefinisikannya sekali.

gbjbaanb
sumber
17
"Satu miliar Amerika atau Eropa?" - "Apa? Aku tidak tahu itu! Ahhhhh !!!!"
Tesserex
Di Inggris, setidaknya, kita sudah lama mengadopsi 1e9 miliar.
Jack Aidley
1
@Tesserex - yah, Anda harus tahu hal-hal ini ketika Anda seorang raja, Anda tahu.
gbjbaanb
5

Alasan untuk tidak

Pertama, inilah alasan mengapa tidak menulis garis bawah atau menggunakan trik apa pun untuk mensimulasikannya: ini membuat konstanta lebih sulit ditemukan dalam kode. Misalkan beberapa program menunjukkan, di suatu tempat dalam operasinya, nilai hard-code 1500000 untuk beberapa parameter. Saya ingin tahu di mana dalam kode sumber program ini sebenarnya terjadi, jadi saya ambil kodenya 1500000, dan tidak menemukan apa pun. Mengapa? Mungkin dalam heksadesimal (tapi mengapa untuk angka desimal bulat). Tanpa sepengetahuan saya, konstanta sebenarnya ditulis sebagai 1_500_000. Saya membutuhkan regex 1_?500_?000.

Membimbing Karakter dalam Komentar

Hanya karena satu jenis alat bantu visual tidak tersedia, atau kami tidak ingin menggunakannya karena alasan di atas, tidak berarti kami tidak dapat memanfaatkan dua dimensi file teks untuk membuat alat bantu visual alternatif:

foo = bar / 1000000000;
//           --^--^--^  

Dengan ini kita dapat dengan mudah meyakinkan diri sendiri bahwa ada tiga kelompok tiga nol. Namun, kami masih dapat menangkap kode sumber untuk 1000000000dan menemukannya.

Pewarnaan Sintaks

Editor teks dengan pewarnaan sintaks yang dapat diprogram dapat dibuat untuk mewarnai kelompok digit dalam konstanta numerik dengan warna bergantian untuk keterbacaan yang lebih baik. Kami tidak perlu melakukan apa pun dalam kode.

Preprocessing: C, C ++, Objective C

Sekarang, jika kita benar-benar menginginkan beberapa koma di antara digit, di C dan C ++ kita dapat menggunakan beberapa preprocessing:

/* Four digit base TH-ousand constant macro */
/* Condensed using Horner's rule */
#define TH(A,B,C,D) ((((((A) * 1000) + (B)) * 1000) + (C)) * 1000 + D)

tv_sec = nanoseconds / TH(1,000,000,000)

Bekerja untuk angka seperti TH(1,234,567,890).

Makro mirip dengan TH juga bisa bekerja dengan token paste daripada aritmatika. Dalam preprocessor C, ##operator biner ("token paste") dapat digunakan dalam tubuh makro untuk menempelkan dua operan menjadi satu token tunggal. Satu atau kedua operan bisa berupa argumen makro. Kelemahan di sini (menciptakan risiko bagi kami) adalah bahwa jika katenasi yang dihasilkan bukan token yang valid, perilaku tidak terdefinisi.

#define TOK4(A, B, C, D) A ## B ## C ## D

Sekarang

TOK4(1,000,000,000)       /* produces the single token 1000000000 */
TOK4(1,123,000,000.0E+2)  /* produces the single token 1123000000.0E+2 */
TOK4(pr,in,t,f)           /* produces the token printf */
TOK4(#,*,a,b)             /* undefined behavior, #*ab is not valid token syntax */

Program C yang menempelkan pengidentifikasi dan menggunakan hasilnya untuk memberi nama variabel global dan fungsi yang ada dan mengerikan untuk bekerja dengan karena mereka tahan terhadap alat-alat seperti GNU id-utils dan ctags.

Kaz
sumber
2
+1 untuk salah satu penyalahgunaan preprosesor terbaik yang pernah saya lihat. Saya masih menggunakan NSEC_PER_SEC atau sesuatu yang sedang diproduksi.
Victor
Hampir -1 untuk menyalahgunakan preprocessor :)
a CVn
3

Ya, itu terdengar seperti ide yang masuk akal. Kesalahan DIGIT off-by-one bahkan lebih buruk daripada kesalahan off-by-one yang terkenal. Meskipun, itu dapat membuat orang lain bingung (termasuk diri Anda di masa depan) untuk membaca kode.

Nama yang lebih jelas seperti NANOSEC_PER_SEC tampaknya bagus, karena akan menambah kejelasan tempat digunakannya waktu. Namun, tidak masuk akal untuk digunakan dalam konteks selain waktu, dan tidak praktis untuk membuat 1.000.000.000 terpisah untuk setiap situasi.

Apa yang benar-benar ingin Anda lakukan, konyol seperti yang terlihat pada awalnya, adalah 'bagi lebih dari sec'. Ini menyisakan NANO_PER, yang tidak hanya bebas bahasa (10 ^ 9 di Amerika dan Eropa) tetapi juga bebas situasi (tidak membatasi unit), dan mudah untuk mengetik dan membaca.

MegaWidget
sumber
posting ini agak sulit dibaca (dinding teks). Maukah Anda mengeditnya menjadi bentuk yang lebih baik?
nyamuk
3

Secara umum adalah ide yang buruk untuk menggunakan konstanta skalar untuk konversi satuan, dan jika Anda mendapati diri Anda membuat konstanta untuk hal-hal seperti itu, Anda melakukan konversi di tempat yang terlalu banyak.

Ketika Anda memiliki jumlah satu unit (katakanlah, 10 detik), dan ingin mengkonversi ke unit lain (yaitu nanodetik); inilah saat yang tepat untuk menggunakan sistem jenis bahasa Anda untuk memastikan bahwa unit benar-benar diskalakan sesuai keinginan Anda.

Membuat fungsi Anda mengambil Nanosecondsparameter, dan menyediakan operator konversi dan / atau konstruktor di kelas itu untuk Seconds, Minutes, atau apa-Anda-. Di sinilah Anda const intatau #defineatau 1e9terlihat dalam jawaban lainnya milik.

Ini menghindari variabel unit ambigu yang mengambang di sekitar kode Anda; dan mencegah seluruh petak bug dari tempat penggandaan / pembagian yang salah diterapkan, atau sudah diterapkan, atau kuantitas sebenarnya jarak bukannya waktu, atau ...

Juga, di kelas-kelas seperti itu ada baiknya membuat konstruksi dari skalarsprivate biasa dan menggunakan statis "MakeSeconds (int)" atau serupa untuk mencegah penggunaan nomor buram yang ceroboh.

Lebih khusus untuk contoh Anda, di C ++ lihat Boost.Chrono .

nilai
sumber
1
+ Paling tidak, gunakan tipe umum dengan faktor penskalaan atau offset dari basis, seperti zona waktu yang sering difitnah.
JustinC
1

Saya pribadi tidak akan menganggap itu praktik yang baik untuk membuat konstanta kecuali jika harus konstan. Jika itu akan berada di beberapa tempat dan menetapkannya di bagian atas file untuk modifikasi / atau pengujian akan berguna maka benar-benar.

Jika itu hanya karena canggung mengetik? lalu tidak.

Secara pribadi jika saya mendapatkan kode orang lain yang memiliki konstanta yang didefinisikan, saya biasanya menganggap ini sebagai aspek penting dari kode. Misalnya tcp menjaga timer hidup, jumlah koneksi maksimum diperbolehkan. Jika saya harus men-debug itu, saya mungkin akan membayar banyak perhatian yang tidak dibutuhkan untuk itu mencoba mencari tahu mengapa / di mana itu digunakan.

Simon McLoughlin
sumber
Saya mendapatkan lelucon tetapi jika programmer bank harus membuat konstan untuk setiap nomor yang Anda dapat mentransfer perangkat lunak akan menjadi raksasa, tidak terkendali dan lambat. Saya hanya bisa membayangkan bagaimana jadinya, bayangkan diberi tahu akan membutuhkan waktu 3 hari kerja untuk mentransfer uang ke .... OH ALLAH SAYA, ITULAH !!!
Simon McLoughlin
Bank saya membutuhkan waktu 3 hari untuk mentransfer uang :(
Reactgular
1
@MathewFoscarini bankir menggunakan Excel mereka tidak perlu programmer;)
Mateusz
@Simon Tergantung pada bahasa dan kompiler, konstanta harus dioptimalkan ke dalam kode, menimbulkan sedikit overhead. Saya mengerti maksud Anda, tetapi konstanta dapat digunakan di mana saja menggunakan nama, bukan angka ajaib akan membantu pembacaan kode.
Steven
Canggung membaca jauh lebih merupakan masalah daripada canggung mengetik.
Alb
0

Ketika Anda memikirkan mengapa Anda menulis "1 Miliar" dan bukan "1000000000" di judul pertanyaan Anda, Anda akan menyadari mengapa jawabannya adalah ya.

Alb
sumber
0

Jangan membuat konstanta untuk literal besar Anda. Anda akan membutuhkan konstanta untuk setiap literal tersebut, yang (menurut saya) adalah lelucon yang lengkap. Jika Anda benar-benar perlu membuat literal Anda lebih jelas tanpa bantuan hal-hal seperti penyorotan sintaks, Anda dapat (walaupun saya tidak mau) membuat fungsi atau makro untuk membuat hidup Anda "lebih mudah":

#define SPLIT3(x, y, z) x##y##z

int largeNumber1 = SPLIT3(123,456,789);
int largeNumber2 = 123456789;
Thomas Eding
sumber
0

Saya akan melakukan ini:

const int Million = 1000 * 1000;
const int Billion = 1000 * Million;

atau

const int SciMega = 1000 * 1000; const int SciGiga = 1000 * SciMega;

Mengenai jumlah nanodetik per detik: nano adalah "kebalikan" dari giga.

Kilo  Mega  Giga   etc.
10^3  10^6  10^9
Milli Micro Nano   etc.
10^-3 10^-6 10^-9

Perhatikan "Sains" - untuk ilmiah, seperti di komputer, arti kilo, mega, giga dll berbeda: 1024 (2 ^ 10), 1024 * 1024 (2 ^ 20), dll. 2 megabita bukan 2.000.000 byte .

UPDATE Commenter menunjukkan bahwa ada istilah khusus untuk eksponen digital 2: http://en.wikipedia.org/wiki/Mebibyte

Tuan TA
sumber
"2 megabita bukan 2.000.000 byte." Tanyakan produsen hard disk pemintalan yang Anda inginkan. (Bukan downvoter, btw.)
CVn
@michaelkjorling ini adalah pertanyaan pemrograman, bukan etika bisnis atau pemasaran. Saya setuju tentang hard drive, tapi itu topik yang berbeda. Dan aduh tentang suara turun!
Tn. TA
1
Sebenarnya, 2 Megabita adalah 2.000.000 byte. 2 Mebibytes adalah 2.097.152 byte. Lihat en.wikipedia.org/wiki/Mebibyte
vy32
@ vy32 terima kasih, belum pernah mendengar itu sebelumnya. Akan memperbarui jawaban saya untuk mencerminkan itu.
Tn. TA
@ Mr.TA, tidak masalah! Kami bekerja keras untuk membawa Ilmu Komputer sesuai dengan SI Unit! Bergabung dengan klub.
vy32