Tam sayı sabitlerinde alt çizgi bulunmasına izin vermeyen dillerde, 1 milyar için bir sabit oluşturmak iyi bir uygulama mıdır?


39

Tamsayı değişmezlerin alt çizgi yapmasına izin vermeyen dillerde, 1 milyar için bir sabit oluşturmak iyi bir fikir midir? örneğin, C ++ 'da:

size_t ONE_BILLION = 1000000000;

Kuşkusuz, 100 gibi küçük sayılar için sabitler yaratmamalıyız. Fakat 9 sıfırla, sıfır gibi bırakmak ya da böyle bir kodda fazladan bir tane eklemek tartışmalı olarak kolaydır:

tv_sec = timeInNanosec / 1000000000;
tv_nsec = timeInNanosec % 1000000000;

24
Ben umut herkes burada oy veren NO . Bu şekilde, belki bir gün bankam hesabıma bir milyar dolar havale edecektir, çünkü bir programcı sabit kullanmamış ve sıfır yerleştirmiş! :)
Tepki

43
Neden küçük sayılar için sabitler oluşturmuyorsunuz? 100 ne anlama geliyor? Bazı bağlamlar yoksa, sihirli bir sayıdır.
Allan,

4
@MathewFoscarini Genel olarak, hatalar iki yönlü de olabilir. Ancak, bankanıza gelince, hatalar her zaman size karşı olacaktır.
emory

23
Düşünün yazma 1e9, 10^9ya da 1_000_000_000dile eğer destekleri o kullanıyor.
Hammar

Yanıtlar:


33

Çoğu dilde bir çeşit üstel gösterim vardır. Bir milyon 1e6(1 ila 10, 6'nın gücüne karşılık gelir). Bu temelde meseleyi, buradaki önerilerin çoğundan daha iyi çözer.

Bir çok C-benzeri dilde, bilimsel gösterim , gerçekten bir int ihtiyacınız varsa talihsiz bir kayan nokta türü tanımlamaktadır . Ancak, formülerinizde gizli dönüşümleri önlemek için bu sabiti kolayca yazabilirsiniz.

n / int(1e9) bir milyar ile bölecekti.

Örneğinizde fiziksel niceliklerle (nanosaniye cinsinden zaman) ilgilenmekle, kendime tamsayının doğru tip olup olmadığını sordum. Aslında double, ölçülebilir miktarlarla uğraşırken kayan bir nokta daha uygun olabilir (elbette a'yı tercih ettiğiniz durumlar olsa da long long).


6
NANOSECONDS_IN_ONE_SECOND çözümünün çok daha net ve düzgün olduğunu düşünüyorum
Thomas Bonini

1
Soru tamsayılı liberallerle ilgiliydi ve bilimsel gösterimi kullanmayı öneriyorum. Bunu yerinde yapmak ya da bir sabit tanımlamak, soruda istenmeyen bir yapılandırma kodudur. Bir sabiti tanımlanması sınırlı soyutlama, ben daha iyi soyutlama elde etmek makro dönüştürme işlevini / yazardı ekler
wirrbel

1
çok büyük bir çifte bir int yapmak, kayan nokta sayılarının tipik yuvarlama farkı problemlerini riske atmaz mı?
Philipp

normal kesinlikli tamsayı tiplerinde, dönüştürmek için çift kesinlikli bir şamandıra kullandığınız sürece bu bir sorun olmamalıdır. long longAralığın değerlerini kullanırken haklısınız .
wirrbel

145

Temsil ettiği yerine NANOSECONDS_IN_ONE_SECOND adlı bir tane oluşturun.

Ya da daha kısa, daha iyi bir isim varsa düşünebilirsiniz.


58
Ben söyleyebilirim Nanoseconds_Per_Secondama bu, bence, doğru cevap.
KChaloux

8
@Matthew Ben senin fikrini anlamıyorum. Metre başına milimetre demekte yanlış bir şey yok. Bunun gereksiz olduğunu ima ediyor olabilirsiniz, bu nanosaniyede saniyede bir milyar kesir atar, ancak tekrar belirtmekte yanlış bir şey yoktur. Bu, 1 + 1 = 2
demek

7
@MathewFoscarini Aslında, hayır, bu bağlamda değil. Öyleyse, NANOSECONDSneye başvurması gerektiğini söyleyemediğiniz için adlandırılmış bir sabit anlamsızdır. Aynı şekilde, NANOSECONDS_PER_MICROSECONDmantıklı bir benzer geçerli bir sabittir.
Izkata

5
@MathewFoscarini, "metre başına milimetre" ham değeri elde etmek için dönüşümdeki birimi kaldırmanın bir yoludur. 1mm/1m = 1000, burada tam olarak ne yapıldığına da dikkat çekiliyor.
zzzzBov

11
Neden bu kadar çok yazıyorsun? NS_PER_SECnanosaniye ile uğraşması gereken herkes için net olmalıdır.
Rex Kerr

67

Sabitler rakamlara anlam vermek içindir. Bunun başka bir anlamı ONE_BILLIONyok 1000000000. Aslında, daha kafa karıştırıcıdır, çünkü farklı doğal dillerde, bir milyar farklı bir şey demektir (bin milyon ya da milyon milyon)! Daha kısa yazmak istiyorsanız, programlama dilinizin bilimsel gösterimi kullanmasına izin vermesi iyi bir olasılıktır, örn 1e9. Aksi takdirde, @JoB ile aynı fikirdeyim, bu sayı gerçekten bir saniye cinsinden nanosaniye sayısı anlamına geliyor, bu yüzden bunu adlandırın.


9
Farklı dillerde milyarın sıfır olduğu anlamına geldiğine işaret etmek güzel.
frozenkoi

3
normal dilleri doğal dillere çevirmeyi öneririm. Düzenli başka bir şey anlamına gelir ...
jk.

Dilde "milyar" farklı yorumu çok iyi bir nokta! Neden cevabını iki kere alamıyorum?
DSF

3
Farklı dillere ihtiyacınız yok. Farklı ülkelere bile ihtiyacınız yok. İngiliz İngilizcesinde "milyar", resmi iletişimde (kitle iletişim araçları ve hükümet) 1974'ten önce ve sonra farklı bir şey ifade ediyor ve her iki kullanım hala var.
Jörg W Mittag

1
" 10000000000. için ONE_BILLION herhangi bir ek anlamı yoktur ben katılmıyorum (İpucu: Ben kasten sizi misquoted ve başka sıfır katma; o bahsedilen olmasaydı fark etmiş olurdu?)..
Keith Thompson

27

Bir veya iki kullanım için sözleşmeyi kullanırdım:

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

Mükemmel bir şekilde kendini açıklayıcı, sabit bir şekilde derlenmiş ve parçalanması zor.

Ayrıca, bu gibi durumlarda çok yararlıdır:

var Time = 24 * 60 * 60;

görmek kolay nerede saniyede bir gün hakkında konuşuyorsun.


Genelde yaptığım şey bu. Ayrıca dün NANOSECONDS_IN_ONE_SECOND tanımladığımı ve bugün NANOSECONDS_PER_SECOND tanımladığımı da unutmayacağım avantajı var. Ve yarın belki de ONE_AMERICAN_BILLION.
Thomas Padron-McCarthy

Şüphesiz 'SecondsInOneDay = 24 * 60 * 60' daha kolay mı?
JBRWilkinson

@JBRWilkinson eminim, ilk snippet'im bir sınıf kullanıyordu instance.Time = ..., ama sonra bıraktım ...
Sklivvz

3
C veya C ++ dilinde, yalnızca 16 bit olması gereken (1000 * 1000 * 1000)türden bir intveri olduğundan taşabilir. Bundan (1000L * 1000L * 1000L)kaçınmak için yazabilirsiniz .
Keith Thompson,

Bunu çok yapıyorum. Çok iyi çalışıyor.
vy32

10

Değerin uzunluğu, sabitin gerekli olup olmadığını tanımlayan şey değildir.

Sihirli sayılardan kaçınmak için sabitleri kullanırsınız , yazmaktan kaçının.

Örneğin, bunlar tamamen geçerli sabitler:

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;

kullanın:

public static final int NANOSECS_PER_SECOND = 1000000000;

(kod örnekleri Java’dadır, en sevdiğiniz dile çevirin)


3
+1 İsimli numaralar neredeyse işe yaramaz. Sabitlerin amacı bu sayılara anlam kazandırmaktır. Neyi temsil ediyorlar? Hangi şeyi sayarlar, sınırlarlar ya da resmi olarak adlandırılmış katsayılar? Sayımın değeri ne değil.
JustinC


2
Bunlar geçerli sabitlerin korkunç örnekleri. İsimlerden önce yaratılmaları dışında, emirler olmalıydı.
Christoffer Hammarström

@ ChristofferHammarström Gerçekten de enums'lardan önce yaratılmışlar, Java SDK'nın SQL paketinde ResultSet sınıfının bir parçası.
Tulains Córdova

2
@ ChristofferHammarström Onlar kötüler çünkü artık kundaklarımız var ama ayrılmaz olmak için değiliz. Bu sınıflar oluşturulduğunda Enum yoktu ve FETCH_FORWARD ve FETCH_REVERSE gibi birbirini dışlayan seçenekler arasında ayrım yapmak için onlara farklı bir değer veriyor. Değer önemli değil, sadece farklı olmaları gerçeği.
Tulains Córdova

8

Bir Amerikalı mı yoksa Avrupalı ​​milyar mı?

(veya teknik açıdan, kısa veya uzun ölçekte bir milyar - biri 1000 milyon, diğeri bir milyon milyondur).

Bu karışıklık göz önüne alındığında, evet derdim - bir kez tanımlamak ve onunla devam etmek mantıklıdır, aynı şekilde tanımını kabul etmek için ihtiyaç duyduğunuz herhangi bir sabit için de geçerlidir - bir kez tanımlayın.


17
"Bir Amerikan mı yoksa Avrupa milyar mı?" - "Ne? Bilmiyorum! Ahhhhh !!!!"
Tesserex

İngiltere'de en azından 1e9 milyarı kabul ettiğimizi uzun zamandır kabul ediyoruz.
Jack Aidley

1
@Tesserex - iyi, bir kral olduğunuzda bunları bilmek zorundasınız, biliyorsunuz.
gbjbaanb

5

Olmama Nedenleri

Öncelikle, burada simüle etmek için herhangi bir alt çizgi yazmamak ya da herhangi bir numara kullanmamak için bir neden: sabitleri kodda bulmayı zorlaştırıyor. Bazı programların çalışmasının bir yerinde, bazı parametreler için 1500000 kodlanmış değer gösterdiğini varsayalım. Bu programın kaynak kodunda gerçekte nerede gerçekleştiğini bilmek istiyorum, bu yüzden kodu okuyorum 1500000ve hiçbir şey bulamadım. Neden? Onaltılık (ancak böyle bir yuvarlak ondalık sayı için neden) olabilir. Bana göre, sabit aslında olarak yazılmıştır 1_500_000. Regex'e ihtiyacım vardı 1_?500_?000.

Yorumdaki Karakterleri Rehberlik Etme

Sadece bir çeşit görsel yardım bulunmadığı veya yukarıdaki nedenlerden dolayı kullanmak istemediğimizden, alternatif bir görsel yardım oluşturmak için metin dosyasının iki boyutundan yararlanamayacağımız anlamına gelmez:

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

Bununla kendimizi üç sıfır grubun olduğu konusunda rahatlıkla ikna edebiliriz. Yine de, kaynak kodunu hala 1000000000bulabilir ve bulabiliriz.

Sözdizimi Renklendirme

Programlanabilir sözdizimi renklendirmeli bir metin editörü daha iyi okunabilmesi için basamakları nümerik sabitler halinde değişen renklerle renklendirmek için yapılabilir. Kodda hiçbir şey yapmak zorunda değiliz.

Ön işleme: C, C ++, Amaç C

Şimdi, basamaklar arasında gerçekten virgül istiyorsak, C ve C ++ 'da ön işleme kullanabiliriz:

/* 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)

Gibi sayılar için çalışıyor TH(1,234,567,890).

TH'ye benzer bir makro da aritmetik değil, token yapıştırma ile de çalışabilir. C önişlemcisinde, ##iki işleci tek bir tonada yapıştırmak için ikili operatör ("token paste") bir makro gövdede kullanılabilir. İşlenenlerden biri veya her ikisi de makro argümanlar olabilir. Buradaki dezavantaj (bizim için bir risk oluşturmaktır) ortaya çıkan katener geçerli bir belirteç değilse, davranış tanımsızdır.

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

şimdi

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 */

Tanımlayıcıları bir araya getiren ve sonuçları global değişkenleri ve fonksiyonları isimlendirmek için kullanan C programları mevcuttur ve çalışmak için zordur çünkü GNU id-utils ve ctags gibi araçlara karşı hassastırlar.


2
İşlemcinin en iyi suiistimallerinden biri için +1 gördüm. Yine de NSEC_PER_SEC ile ya da yapımdaki bir şeyle giderdim.
Victor,

Çok neredeyse -1 ön işlemci :) tacizde
Bir CVn

3

Evet, makul bir fikir gibi geliyor. Off-by-one DIGIT hataları rezil off-by-one hatalarından bile daha kötü. Bununla birlikte, diğer insanların (gelecekteki benliğiniz de dahil) kodu okuması için karışıklık yaratabilir.

NANOSEC_PER_SEC gibi daha açıklayıcı bir isim, zaman için kullanıldığı yerde netlik katacağı için iyi görünüyor. Bununla birlikte, zaman dışındaki bağlamlarda kullanılmasının bir anlamı yoktur ve her durum için ayrı bir 1.000.000.000 oluşturmak pratik değildir.

Gerçekten yapmak istediğin, ilk bakışta göründüğü gibi aptalca, 's bölü bölme' olur. Bu, yalnızca dilden bağımsız (Amerika ve Avrupa'da 10 ^ 9) değil aynı zamanda durumdan bağımsız (birimler üzerinde sınırlama yoktur) ve yazması ve okuması kolay olan NANO_PER'yi bırakır.


Bu yazı okumak oldukça zordur (metin duvarı). Sakıncası var düzenleyebilir daha iyi bir şekle ing?
tatarcık

3

Genel olarak birim dönüşümler için skaler sabitleri kullanmak kötü bir fikirdir ve kendinizi bu tür şeyler için sabitleştiriyorsanız çok fazla yerde dönüşüm yapıyorsunuzdur.

Bir birim miktarınız varsa (örneğin, 10 saniye) ve başka bir birime (yani nanosaniye) dönüştürmek istediğinizde; tam olarak, birimlerin gerçekten istediğiniz gibi ölçeklendirilmesini sağlamak için dilinizin tür sistemini kullanmanın tam zamanıdır.

Fonksiyonun bir alacak olun Nanosecondsparametreyi ve söz konusu sınıfta dönüşüm operatörleri ve / veya kurucular sağlamak Seconds, Minutesya da ne-si-sen. Senin burasıdır const intveya #defineveya 1e9diğer cevaplar görülen aittir.

Bu, kodunuzun etrafında yüzen belirsiz birimlerin değişkenlerinin bulunmasını önler; ve yanlış çarpma / bölmenin uygulandığı ya da zaten uygulandığı ya da miktarın zaman yerine aslında mesafe olduğu ya da ...

Ayrıca, bu tür sınıflarda düz skalerden özel yapım yapmak ve statik olmayan bir "MakeSeconds (int)" kullanmak veya opak sayıların caydırıcı olmayan özensiz kullanımına benzer.

Daha spesifik olarak, örneğinize göre, C ++ 'da Boost.Chrono'yu inceleyin .


1
+ En azından, çoğu zaman kötü huylu zaman dilimine benzer şekilde, temelden bir ölçekleme veya ofset faktörü ile ortak bir tip kullanın.
JustinC

1

Şahsen, sabit olması gerekmedikçe, bir sabit yaratmanın iyi bir uygulama olduğunu düşünmezdim. Birden fazla yerde olması ve dosyanın üst kısmında tanımlanması ve / veya test edilmek üzere tanımlanmış olması kesinlikle yararlı olacaktır.

Sadece onun için yazmak için garip çünkü? o zaman hayır.

Şahsen, tanımlanmış sabiti olan bir başkasının kodunu alırsam, bunun genellikle kodun önemli bir yönü olduğunu düşünüyorum. Tcp, zamanlayıcıları canlı tutar, izin verilen maksimum bağlantı sayısını sağlar. Eğer hata ayıklamak zorunda kalsaydım, neden / nerede kullanıldığını anlamaya çalışırken muhtemelen çok fazla dikkat etmem gerekirdi.


Şakayı anlıyorum ama banka programcıları her numara için bir sabit yapmak zorunda kalırsa yazılımı devredebilir, yönetilemez ve yavaş olurdu. Bunun nasıl olacağını hayal edebiliyorum, para transferinin 3 iş günü alacağını söylendiğini hayal et.
Simon McLoughlin


1
@MathewFoscarini bankacıları programcılara ihtiyaç duymayan Excel kullanıyorlar;)
Mateusz

@Simon Dile ve derleyiciye bağlı olarak, sabitler küçük ek yükler olacak şekilde koda göre optimize edilmelidir. Amacınızı anlıyorum, ancak sihirli bir numara yerine bir ad kullanıldığında kod okunabilirliğine yardımcı olacağı yerlerde sabitler kullanılabilir.
Steven,

Okumak garip bir yazı yazmaktan ziyade fazla bir konudur.
Alb,

0

Soru başlığınızda neden "1000000000" yerine "1 Milyar" yazdığını düşündüğünüzde, cevabın neden evet olduğunu anlayacaksınız.


0

Büyük değişmezleriniz için bir sabit yaratmayın. Böyle bir kelimenin tam anlamıyla bir sabite ihtiyacınız olacak, (bence) tam bir şaka. Umutsuzca, sözdizimi vurgulama gibi şeylerin yardımı olmadan edebi dilinizi daha net hale getirmeniz gerekirse, ("yapmasam da) hayatınızı" kolaylaştırmak "için işlevler veya makrolar oluşturabilirsiniz:

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

int largeNumber1 = SPLIT3(123,456,789);
int largeNumber2 = 123456789;

0

Bunu yapardım:

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

veya

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

Saniyedeki nanosaniye sayısıyla ilgili olarak: nano, giga'nın "tersi" dir.

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

Bilimsel, "Sci" - bilgisayarlarda olduğu gibi kilo, mega, giga vb. Anlamları farklıdır: 1024 (2 ^ 10), 1024 * 1024 (2 ^ 20), vb. 2 megabayt 2.000.000 bayt değildir. .

GÜNCELLEME Yorumcu 2 dijital üsleri için özel terimlerin bulunduğunu belirtti: http://en.wikipedia.org/wiki/Mebibyte


"2 megabayt 2.000.000 bayt değil." İstediğiniz herhangi bir döner tabla sabit disk üreticisine danışın. (Downvoter değil, btw.)
bir CVn

@michaelkjorling bu bir programlama sorusudur, bir iş ahlakı veya pazarlama sorusudur. Sabit diskler konusunda hemfikirim ama bu farklı bir konu. Ve aşağı oy hakkında ouch!
Bay TA,

1
Aslında, 2 Megabayt 2.000.000 bayttır. 2 Mebibitten 2.097.152 bayttır. Bakınız en.wikipedia.org/wiki/Mebibyte
vy32

@ vy32 teşekkürler, daha önce hiç duymadım. Bunu yansıtmak için cevabımı güncelleyeceğim.
Bay TA,

@ Mr.TA, sorun değil! Computer Science'ı SI Üniteleri ile uyumlu hale getirmek için çok çalışıyoruz! Kulübe katıl.
vy32
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.