Trong các ngôn ngữ không cho phép dấu gạch dưới trong hằng số nguyên, có phải là một cách thực hành tốt để tạo hằng số cho 1 tỷ?


39

Trong các ngôn ngữ không cho phép gạch dưới bằng số nguyên , có nên tạo hằng số cho 1 tỷ không? ví dụ: trong C ++:

size_t ONE_BILLION = 1000000000;

Chắc chắn, chúng ta không nên tạo các hằng số cho số nhỏ như 100. Nhưng với 9 số không, có thể dễ dàng bỏ đi một số 0 hoặc thêm một số bổ sung vào mã như thế này:

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

24
Tôi hy vọng tất cả mọi người ở đây bỏ phiếu cho NO . Bằng cách đó, có thể một ngày nào đó ngân hàng của tôi sẽ chuyển một tỷ đô la vào tài khoản của tôi vì một lập trình viên đã không sử dụng hằng số và đặt sai số 0! :)
Phản ứng

43
Tại sao không tạo hằng số cho số lượng nhỏ? 100 có nghĩa là gì? Trừ khi có một số bối cảnh, đó là một con số kỳ diệu.
Allan

4
@MathewFoscarini Nói chung, sai lầm có thể đi một trong hai cách. Nhưng khi nói đến ngân hàng của bạn, những sai lầm sẽ luôn đi ngược lại bạn.
emory

23
Xem xét việc viết 1e9, 10^9hoặc 1_000_000_000nếu ngôn ngữ bạn đang sử dụng hỗ trợ nó.
hammar

Câu trả lời:


33

Hầu hết các ngôn ngữ có một số loại ký hiệu số mũ. Một triệu là 1e6, (nghĩa là 1 lần 10 với sức mạnh của 6). Điều này về cơ bản giải quyết vấn đề thậm chí còn tốt hơn hầu hết các đề xuất ở đây.

Trong rất nhiều ngôn ngữ giống như C, ký hiệu khoa học tuy nhiên xác định loại dấu phẩy động , thật không may nếu bạn thực sự cần một int. Tuy nhiên, bạn có thể dễ dàng nhập kiểu không đổi để tránh chuyển đổi ngầm trong công thức của bạn.

n / int(1e9) sẽ chia cho một tỷ.

Trong ví dụ của bạn, xử lý các đại lượng vật lý (thời gian tính bằng nano giây), tôi thường tự hỏi mình liệu số nguyên có phải là loại đúng không. Trong thực tế, một điểm nổi doublecó thể phù hợp hơn khi xử lý các đại lượng có thể đo được (mặc dù có những trường hợp dĩ nhiên bạn muốn a long long).


6
Tôi nghĩ rằng giải pháp NANOSECONDS_IN_ONE_SECOND rõ ràng và gọn gàng hơn nhiều
Thomas Bonini

1
Câu hỏi là về tự do số nguyên và tôi đề xuất sử dụng ký hiệu khoa học. Việc thực hiện điều này tại chỗ hay bằng cách xác định hằng số là một vấn đề về cấu trúc mã không được yêu cầu trong câu hỏi. Xác định một hằng số trừu tượng hóa giới hạn, tôi sẽ viết một hàm chuyển đổi / macro để đạt được sự trừu tượng hóa tốt hơn
wirrbel

1
sẽ tăng gấp đôi rất lớn cho một int không có nguy cơ các vấn đề khác biệt làm tròn điển hình của số dấu phẩy động?
Phi

với các loại số nguyên có độ chính xác bình thường, đây không phải là vấn đề miễn là bạn sử dụng số float chính xác kép để chuyển đổi từ. bạn đúng khi sử dụng các giá trị của long longphạm vi.
wirrbel

145

Tạo một cái gọi là NANOSECONDS_IN_ONE_SECOND thay vì đó là những gì nó đại diện.

Hoặc một tên ngắn hơn, tốt hơn nếu bạn có thể nghĩ về một cái.


58
Tôi muốn nói Nanoseconds_Per_Secondnhưng theo tôi, đây là câu trả lời đúng.
KChaloux

8
@Mathew Tôi không nhận được quan điểm của bạn. Không có gì sai khi nói milimet trên mét. Bạn có thể ngụ ý rằng nó là dư thừa, trong vài nano giây đó, một tỷ phân số của một giây, nhưng không có gì sai khi nói lại. Giống như nói 1 + 1 = 2. "x mỗi y" tiếp tục có ý nghĩa hơn khi x và y rời rạc, như "đơn vị trên nửa tá" hoặc "nano giây trên mili giây"
Mark Canlas

7
@MathewFoscarini Thật ra, không, trong bối cảnh này thì không. Nếu đúng như vậy, một hằng số được đặt tên NANOSECONDSlà vô nghĩa vì bạn không thể biết nó được áp dụng cho cái gì. Tương tự như vậy, NANOSECONDS_PER_MICROSECONDlà một hằng số hợp lệ tương tự có ý nghĩa.
Izkata

5
@MathewFoscarini, "milimet trên mét" là cách xóa đơn vị trên chuyển đổi để lấy giá trị thô. 1mm/1m = 1000, đó chính xác là điểm của những gì đang được thực hiện ở đây.
zzzzBov

11
Tại sao gõ quá nhiều? NS_PER_SECnên rõ ràng đối với bất cứ ai phải xử lý nano giây.
Rex Kerr

67

Hằng số có nghĩa là để cho số ý nghĩa. Không có bất kỳ ý nghĩa bổ sung trong ONE_BILLIONđể 1000000000. Trên thực tế, nó làm cho nó khó hiểu hơn, bởi vì trong các ngôn ngữ tự nhiên khác nhau, một tỷ có nghĩa là một cái gì đó khác nhau (có thể là một triệu triệu hoặc một triệu triệu)! Nếu bạn muốn viết nó ngắn hơn, rất có thể ngôn ngữ lập trình của bạn cho phép sử dụng ký hiệu khoa học, nghĩa là 1e9. Mặt khác, tôi đồng ý với @JohnB, rằng con số này thực sự có nghĩa là số lượng nano giây trong một giây, vì vậy hãy đặt tên cho nó.


9
Điểm tốt là tỷ trong các ngôn ngữ khác nhau có nghĩa là số không khác nhau.
Frozenkoi

3
sẽ đề nghị thay đổi ngôn ngữ thông thường sang ngôn ngữ tự nhiên. thông thường có nghĩa là một cái gì đó khác ...
jk.

Giải thích khác nhau của "tỷ" trong các ngôn ngữ như một điểm tốt! Tại sao tôi không thể đưa ra câu trả lời của bạn hai lần!
DSF

3
Bạn không cần các ngôn ngữ khác nhau. Bạn thậm chí không cần các quốc gia khác nhau. Trong tiếng Anh Anh, "tỷ" có nghĩa là một cái gì đó khác nhau trước và sau năm 1974 trong truyền thông chính thức (phương tiện truyền thông đại chúng và chính phủ), và cả hai cách sử dụng vẫn tồn tại.
Jörg W Mittag

1
" Không có bất kỳ ý nghĩa bổ sung trong ONE_BILLION để 10000000000. Tôi không đồng ý (Gợi ý: Tôi cố tình trích dẫn sai bạn và thêm một zero; sẽ nhận thấy nếu tôi không đề cập đến nó?)..
Keith Thompson

27

Đối với một hoặc hai cách sử dụng, tôi sẽ sử dụng quy ước:

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

Nó hoàn toàn tự giải thích, được biên dịch thành một hằng số và thật khó để bắt vít.

Ngoài ra, nó rất hữu ích trong các trường hợp như:

var Time = 24 * 60 * 60;

nơi dễ thấy chúng ta đang nói về một ngày trong vài giây.


Đây là những gì tôi thường làm. Nó cũng có một lợi thế là tôi sẽ không quên rằng tôi đã xác định NANOSECONDS_IN_ONE_SECOND ngày hôm qua và xác định NANOSECONDS_PER_SECOND ngày hôm nay. Và có lẽ ONE_AMERICAN_BILLION vào ngày mai.
Thomas Padron-McCarthy

Chắc chắn 'SecondsInOneDay = 24 * 60 * 60' vẫn dễ dàng hơn?
JBRWilkinson

@JBRWilkinson chắc chắn, đoạn trích ban đầu của tôi đang sử dụng một lớp instance.Time = ..., nhưng sau đó tôi đã làm nó im lặng ...
Sklivvz

3
Trong C hoặc C ++, (1000 * 1000 * 1000)là loại int, chỉ được yêu cầu là 16 bit, vì vậy nó có thể tràn. Bạn có thể viết (1000L * 1000L * 1000L)để tránh điều đó.
Keith Thompson

Tôi làm điều này rất nhiều. Nó hoạt động rất tốt.
vy32

10

Độ dài của giá trị không phải là thứ xác định xem có cần thiết hay không.

Bạn sử dụng hằng số để tránh số ma thuật , không tránh gõ.

Ví dụ: đây là các hằng số hoàn toàn hợp lệ:

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;

Sử dụng:

public static final int NANOSECS_PER_SECOND = 1000000000;

(các mẫu mã bằng tiếng Java, dịch sang ngôn ngữ yêu thích của bạn)


3
+1 Số được đặt tên gần như vô dụng. Mục đích của hằng số nó mang lại ý nghĩa cho những con số đó. Họ đại diện cho cái gì? Điều gì họ đang đếm hoặc giới hạn hoặc hệ số được đặt tên chính thức? Không phải giá trị của số đếm là gì.
JustinC


2
Đó là những ví dụ khủng khiếp của hằng số hợp lệ. Chúng đáng lẽ là enum, ngoại trừ chúng được tạo ra trước enums.
Christoffer Hammarström

@ Christoffer Hammarström Chúng thực sự được tạo ra trước enums, chúng là một phần của lớp result Set, trong gói SQL của SDK Java.
Tulains Córdova

2
@ Christoffer Hammarström Thật tệ vì bây giờ chúng ta có enum nhưng không phải là không thể đo lường được. Enum đã không tồn tại khi các lớp này được tạo và để phân biệt giữa các tùy chọn loại trừ lẫn nhau như FETCH_FORWARD và FETCH_REVERSE sẽ mang lại cho chúng một giá trị khác. Giá trị không thành vấn đề, thực tế là chúng khác nhau.
Tulains Córdova

8

Một tỷ người Mỹ hay châu Âu?

(hoặc về mặt kỹ thuật, một tỷ ở quy mô ngắn hoặc quy mô dài - một là 1000 triệu, còn lại là một triệu triệu).

Với sự nhầm lẫn này, sau đó tôi sẽ nói đồng ý - thật hợp lý khi xác định nó một lần và tuân theo nó, tương tự áp dụng cho bất kỳ hằng số nào bạn cần để đồng ý định nghĩa trên - xác định nó một lần.


17
"Một tỷ người Mỹ hay châu Âu?" - "Cái gì? Tôi không biết điều đó! Ahhhhh !!!!"
Tesserex

Ở Anh, ít nhất, từ lâu chúng tôi đã nhận được 1e9 tỷ.
Jack Aidley

1
@Tesserex - tốt, bạn phải biết những điều này khi bạn là một vị vua, bạn biết đấy.
gbjbaanb

5

Những lý do không nên

Thứ nhất, đây là một lý do không viết bất kỳ dấu gạch dưới hoặc sử dụng bất kỳ thủ thuật nào để mô phỏng nó: nó làm cho các hằng số khó tìm thấy hơn trong mã. Giả sử rằng một số chương trình trưng bày, ở đâu đó trong hoạt động của nó, giá trị mã hóa cứng 1500000 cho một số tham số. Tôi muốn biết nơi mã nguồn của chương trình này thực sự xảy ra, vì vậy tôi grep mã cho 1500000và không tìm thấy gì. Tại sao? Có thể nó ở dạng thập lục phân (nhưng tại sao lại có số thập phân tròn như vậy). Không biết với tôi, hằng số thực sự được viết là 1_500_000. Tôi cần regex 1_?500_?000.

Nhân vật hướng dẫn trong bình luận

Chỉ vì một loại hỗ trợ trực quan không có sẵn hoặc chúng tôi không muốn sử dụng nó vì lý do trên, không có nghĩa là chúng tôi không thể tận dụng hai chiều của tệp văn bản để tạo một trợ giúp trực quan thay thế:

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

Với điều này, chúng ta có thể dễ dàng thuyết phục bản thân rằng có ba nhóm ba số không. Tuy nhiên, chúng ta vẫn có thể grep mã nguồn 1000000000và tìm nó.

Cú pháp tô màu

Một trình soạn thảo văn bản với màu cú pháp có thể lập trình có thể được thực hiện cho các nhóm màu chữ số trong các hằng số với các màu xen kẽ để dễ đọc hơn. Chúng ta không phải làm bất cứ điều gì trong mã.

Tiền xử lý: C, C ++, Mục tiêu C

Bây giờ, nếu chúng ta thực sự muốn một số dấu phẩy giữa các chữ số, trong C và C ++, chúng ta có thể sử dụng một số tiền xử lý:

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

Hoạt động cho số như TH(1,234,567,890).

Một macro tương tự TH cũng có thể hoạt động với việc dán mã thông báo thay vì số học. Trong bộ tiền xử lý C, ##toán tử nhị phân ("dán mã thông báo") có thể được sử dụng trong phần thân macro để dán hai toán hạng vào một mã thông báo. Một hoặc cả hai toán hạng có thể là đối số macro. Nhược điểm ở đây (tạo ra rủi ro cho chúng tôi) là nếu catenation kết quả không phải là mã thông báo hợp lệ, hành vi không được xác định.

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

Hiện nay

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

Các chương trình C dán các mã định danh lại với nhau và sử dụng các kết quả để đặt tên cho các biến và hàm toàn cục tồn tại và rất tệ khi làm việc vì chúng không phù hợp với các công cụ như GNU id-utils và ctags.


2
+1 cho một trong những lạm dụng tốt nhất của bộ tiền xử lý mà tôi đã thấy. Dù vậy, tôi vẫn sẽ đi với NSEC_PER_SEC hoặc một cái gì đó trong sản xuất.
Victor

Rất gần -1 vì lạm dụng bộ tiền xử lý :)
CVn

3

Vâng, đó có vẻ là một ý tưởng hợp lý. Các lỗi DIGIT by-by-one thậm chí còn tồi tệ hơn các lỗi off-by-one khét tiếng. Mặc dù, nó có thể tạo ra sự nhầm lẫn cho người khác (bao gồm cả bản thân tương lai của bạn) để đọc mã.

Một tên giải thích nhiều hơn như NANOSEC_PER_SEC có vẻ tốt, vì nó sẽ thêm rõ ràng nơi nó được sử dụng cho thời gian. Tuy nhiên, sẽ không có ý nghĩa khi sử dụng trong các bối cảnh khác ngoài thời gian và sẽ không thực tế khi tạo ra 1.000.000.000 riêng cho mọi tình huống.

Điều bạn thực sự muốn làm, ngớ ngẩn như lúc đầu, dường như là 'chia cho giây'. Điều này khiến NANO_PER, không chỉ độc lập với ngôn ngữ (10 ^ 9 ở Mỹ và Châu Âu) mà còn độc lập với tình huống (không giới hạn về các đơn vị), và rất dễ gõ và đọc.


bài này khá khó đọc (tường văn bản). Bạn có phiền chỉnh sửa ing nó thành một hình dạng tốt hơn?
gnat

3

Nói chung, nên sử dụng các hằng số vô hướng cho các chuyển đổi đơn vị và nếu bạn thấy mình tạo các hằng số cho những thứ như vậy thì bạn đang thực hiện chuyển đổi ở quá nhiều nơi.

Khi bạn có số lượng một đơn vị (giả sử là 10 giây) và muốn chuyển đổi sang đơn vị khác (tức là nano giây); đây chính xác là thời gian để sử dụng hệ thống loại ngôn ngữ của bạn để đảm bảo rằng các đơn vị thực sự được thu nhỏ theo ý bạn.

Thực hiện chức năng của mình phải mất một Nanosecondstham số, và cung cấp các nhà khai thác chuyển đổi và / hoặc các hàm trong lớp đó cho Seconds, Minuteshoặc những gì-có-bạn. Đây là nơi bạn const inthoặc #definehoặc 1e9nhìn thấy trong các câu trả lời khác thuộc về.

Điều này tránh việc có các biến của các đơn vị mơ hồ nổi xung quanh mã của bạn; và ngăn chặn toàn bộ các lỗi từ nơi nhân / chia sai được áp dụng hoặc đã được áp dụng hoặc số lượng thực sự là khoảng cách thay vì thời gian, hoặc ...

Ngoài ra, trong các lớp như vậy, tốt nhất là thực hiện xây dựng từ scalarsprivate đơn giản và sử dụng "MakeSeconds (int)" tĩnh hoặc tương tự như không khuyến khích sử dụng các số mờ.

Cụ thể hơn với ví dụ của bạn, trong C ++, hãy xem Boost.Chrono .


1
+ Ít nhất, sử dụng một loại phổ biến với hệ số tỷ lệ hoặc bù từ cơ sở, giống như múi giờ thường bị sai.
JustinC

1

Cá nhân tôi sẽ không coi đó là một thực hành tốt để tạo ra một hằng số trừ khi nó cần phải là một hằng số. Nếu nó sẽ ở nhiều nơi và được xác định ở đầu tệp để sửa đổi / hoặc thử nghiệm thì sẽ hữu ích.

Nếu nó chỉ vì vụng về để gõ? sau đó thì không.

Cá nhân nếu tôi nhận được mã của người khác có hằng số được xác định, tôi thường coi đây là một khía cạnh quan trọng của mã. Ví dụ: tcp giữ bộ hẹn giờ sống, số lượng kết nối tối đa được phép. Nếu tôi phải gỡ lỗi, có lẽ tôi sẽ chú ý rất nhiều đến nó khi cố gắng tìm hiểu tại sao / nơi nó được sử dụng.


Tôi có một trò đùa nhưng nếu các lập trình viên ngân hàng phải tạo ra một hằng số cho mỗi số bạn có thể chuyển phần mềm sẽ là khổng lồ, không thể quản lý và chậm. Tôi chỉ có thể tưởng tượng điều đó sẽ như thế nào, tưởng tượng được nói rằng sẽ mất 3 ngày làm việc để chuyển tiền đến .... OH MY GOD, THATS IT !!!
Simon McLoughlin

Ngân hàng của tôi mất 3 ngày để chuyển tiền :(
Reactgular

1
@MathewFoscarini nhân viên ngân hàng sử dụng Excel mà họ không cần lập trình viên;)
Mateusz

@Simon Tùy thuộc vào ngôn ngữ và trình biên dịch, các hằng số phải được tối ưu hóa thành mã, phát sinh ít chi phí. Tôi hiểu quan điểm của bạn, nhưng hằng số có thể được sử dụng bất cứ nơi nào sử dụng tên thay vì số ma thuật sẽ giúp mã dễ đọc.
Steven

Lúng túng khi đọc là một vấn đề nhiều hơn là lúng túng để gõ.
Alb

0

Khi bạn nghĩ về lý do tại sao bạn viết "1 tỷ" thay vì "1000000000" trong tiêu đề câu hỏi của bạn, bạn sẽ nhận ra lý do tại sao câu trả lời là có.


0

Đừng tạo ra một hằng số cho những chữ lớn của bạn. Bạn sẽ cần một hằng số cho mỗi nghĩa đen như vậy, đó là (theo ý kiến ​​của tôi) là một trò đùa hoàn chỉnh. Nếu bạn rất cần làm cho chữ của bạn rõ ràng hơn mà không cần sự trợ giúp của những thứ như tô sáng cú pháp, bạn có thể (mặc dù tôi sẽ không) tạo các hàm hoặc macro để làm cho cuộc sống của bạn "dễ dàng hơn":

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

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

0

Tôi sẽ làm điều này:

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

hoặc là

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

Về số lượng nano giây mỗi giây: nano là "nghịch đảo" của giga.

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

Lưu ý "Sci" - đối với khoa học, như trong máy tính, ý nghĩa của kilo, mega, giga, v.v ... khác nhau: 1024 (2 ^ 10), 1024 * 1024 (2 ^ 20), v.v. 2 megabyte không phải là 2.000.000 byte .

CẬP NHẬT Bình luận đã chỉ ra rằng các thuật ngữ đặc biệt tồn tại cho số mũ kỹ thuật số của 2: http://en.wikipedia.org/wiki/Mebibyte


"2 megabyte không phải là 2.000.000 byte." Hỏi bất kỳ nhà sản xuất đĩa cứng quay đĩa bạn muốn. (Không phải downvoter, btw.)
CVn

@michaelkjorling đây là một câu hỏi lập trình, không phải là đạo đức kinh doanh hay tiếp thị. Tôi đồng ý về các ổ đĩa cứng, nhưng đó là một chủ đề khác. Và cảm nhận về số phiếu giảm!
Ông TA

1
Trên thực tế, 2 Megabyte là 2.000.000 byte. 2 Mebibytes là 2.097.152 byte. Xem en.wikipedia.org/wiki/Mebibyte
vy32

@ vy32 cảm ơn, chưa bao giờ nghe nói về điều đó trước đây. Sẽ cập nhật câu trả lời của tôi để phản ánh điều đó.
Ông TA

@ Mr.TA, không vấn đề gì! Chúng tôi đang nỗ lực để đưa Khoa học Máy tính tuân thủ các Đơn vị SI! Tham gia vào câu lạc bộ.
vy32
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.