Tại sao viết 1.000.000.000 dưới dạng 1000 * 1000 * 1000 bằng C?


142

Trong mã được tạo bởi Apple, có dòng này:

CMTimeMakeWithSeconds( newDurationSeconds, 1000*1000*1000 )

Có bất kỳ lý do để thể hiện 1,000,000,000như 1000*1000*1000?

Tại sao không 1000^3cho vấn đề đó?


45
Rõ ràng và dễ đọc của mã. Bạn không thể đặt, hoặc 'làm dấu phân cách trong C, vì vậy điều tốt nhất tiếp theo là tính toán giá trị từ phép nhân. ^ là một toán tử không liên quan trong C - độc quyền OR.
Idillotexist Idonotexist

54
nó đặc biệt được sử dụng cho các khoảng thời gian như: 2 * 60 * 60 .. thật dễ dàng nhận thấy đó là trong 2 giờ ..
Idali

53
Đối với một người tôi nghi ngờ 1.000.000.000 không phải là cú pháp hợp lệ
paparazzo

15
Nhân tiện, các ngôn ngữ lập trình hiện đại có cách khác để viết giống nhau, ví dụ như trong Swift 1_000_000_000. Tuy nhiên, với hằng số thời gian thì điều này khó khăn hơn. Nó dễ đọc hơn 30 * 60(30 phút trong giây) so với viết 1800. Thực tế, có những ngôn ngữ sẽ cho phép bạn viết các đơn vị, ví dụ meters, cho phép bạn tự bảo vệ mình trước các bài tập xấu.
Sulthan

29
^là một XOR, không phải là toán tử lũy thừa hoặc lũy thừa.
3Dave

Câu trả lời:


200

Một lý do để khai báo các hằng số theo cách nhân là để cải thiện khả năng đọc, trong khi hiệu suất thời gian chạy không bị ảnh hưởng. Ngoài ra, để chỉ ra rằng người viết đã suy nghĩ theo cách nhân lên về con số.

Xem xét điều này:

double memoryBytes = 1024 * 1024 * 1024;

Rõ ràng là tốt hơn:

double memoryBytes = 1073741824;

như cái nhìn thứ hai không nhìn, thoạt nhìn, sức mạnh thứ ba của 1024.

Như Amin Negm-Awad đã đề cập, ^toán tử là nhị phân XOR. Nhiều ngôn ngữ thiếu toán tử lũy thừa thời gian biên dịch tích hợp, do đó nhân lên.


13
Và trong các ngôn ngữ có toán tử lũy thừa, nó không nhất thiết phải là '^'. Ví dụ, ở Fortran, đó là '**'.
jamesqf

4
Bạn cũng nên bao gồm một liên kết trỏ đến cảnh báo quan trọng, được đưa ra trong câu trả lời dưới đây, từ @chux: stackoverflow.com/a/40637622/1841533 (đặc biệt là OP được gắn thẻ "c", rất dễ bị ảnh hưởng bởi bàn tay này hoạt động bên dường như có tất cả các điều khoản giới hạn trong một loại nhỏ hơn, và do đó phép nhân có thể tràn ra 'vấn đề). securecoding.cert.org/confluence/display/c/ khuyên có thể giúp tránh những người trong trường hợp chung?
Olivier Dulac

4
Ngoài ra chúng ta nên lưu ý rằng việc tính toán được thực hiện tại thời điểm biên dịch. Tiêu chuẩn C yêu cầu triển khai để có thể tính toán các biểu thức hằng trong thời gian biên dịch cho các tính năng khác nhau của ngôn ngữ và chúng ta có thể giả định rằng nó đúng khi sử dụng biểu thức hằng như trong ví dụ này.
ouah

13
Lưu trữ số lượng bộ nhớ là gấp đôi? Đó dường như là một nguồn tiềm năng của lỗi.
JAB

7
@supercat Tôi biết điều đó, nhưng bằng cách sử dụng gấp đôi, bạn có thể gặp trường hợp, giả sử, bạn muốn có một phần của phạm vi bộ nhớ, bạn chia xcho để có kích thước của phân vùng ... và đột nhiên bạn có một phân số byte, có thể yêu cầu logic bổ sung để bù cho.
JAB

73

Tại sao không 1000^3?

Kết quả 1000^3là 1003. ^là toán tử bit-XOR.

Ngay cả nó không đối phó với chính Q, tôi thêm một sự làm rõ. x^ykhông phải lúc nào cũng đánh giá x+ynhư trong ví dụ của người hỏi. Bạn phải xor mỗi bit. Trong trường hợp ví dụ:

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

Nhưng

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

3
thưa ngài, tôi không rõ 1003 ^ 3 là 1003. Máy tính Google và Mac hiển thị 1000 ^ 3 = 1.000.000.000. bạn có thể giải thích?
Mahesh

57
Các ^phương tiện điều hành XOR trong C / C ++ / Objective-C, vv Trong máy tính nó thường có nghĩa là x-to-the-y điện.
Tamás Zahola

5
Bah, các bit 1000 và 3 không trùng nhau. Ngoại hình này rất sai.
Yakk - Adam Nevraumont

19
Các bit làm chồng chéo. Nhưng không phải là 1. : -]
Amin Negm-Awad

6
@Yakk: quả thật là có vẻ sai rồi! ... Tôi hy vọng nhiều người sẽ không nghĩ rằng "A ^ B" luôn mang lại cho A + B (nhưng tôi sợ một số có thể ...)
Olivier Dulac

71

Có những lý do không sử dụng 1000 * 1000 * 1000.

Với 16-bit int, 1000 * 1000tràn. Vì vậy, sử dụng 1000 * 1000 * 1000làm giảm tính di động.

Với 32-bit int, dòng mã đầu tiên sau đây tràn ra.

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

Đề xuất rằng giá trị khách hàng tiềm năng phù hợp với loại điểm đến về tính dễ đọc, tính di động tính chính xác.

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

Cũng có thể sử dụng eký hiệu đơn giản cho các giá trị có thể biểu diễn chính xác như một double. Tất nhiên, điều này dẫn đến việc biết doublechính xác có thể đại diện cho toàn bộ giá trị số hay không - điều đáng quan tâm với các giá trị lớn hơn 1e9. (Xem DBL_EPSILONDBL_DIG).

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

5
Nhận xét rất quan trọng! securecoding.cert.org/confluence/display/c/ khuyên có thể giúp ích trong rất nhiều trường hợp?
Olivier Dulac

2
A doublecó thể biểu diễn chính xác tất cả các số nguyên lên tới 2 ^ 53 9e15.
Edgar Bonet

3
@EdgarBonet Đúng là binary64 có thể biểu thị toàn bộ số lên tới khoảng 9e15. Nhưng C không chỉ định doublesử dụng binary64, mặc dù nó được sử dụng rất phổ biến. Theo thông số kỹ thuật C, các giá trị lên tới 1e9 hoặc hơn là chính xác. Nó phụ thuộc nếu bạn muốn mã để đặc tả hoặc dựa vào thực tiễn phổ biến.
chux - Tái lập Monica

4
@Patrick Cả 10001000000000000hằng số nguyên . Mỗi loại độc lập với loại được chọn từ int, longhoặc long long. Trình biên dịch sử dụng loại đầu tiên của 3 trong đó hằng số nguyên phù hợp. 1000 * 1000 * 1000 * 1000được thực hiện với inttoán học như mỗi 1000trong một int. Sản phẩm tràn 32 bit int. 1000000000000 chắc chắn là đại diện như một long long(hoặc có thể hẹp hơn) - không tràn. Loại mục tiêu long long Durationkhông ảnh hưởng đến "bên phải của sự hủy diệt" này.
chux - Tái lập Monica

2
Đặt loại rộng hơn trước trong phép nhân là rất quan trọng. Với 16-bit int, long x = 1000 * 1000 * 1000L;sẽ tràn, trong khi long x = 1000L * 1000 * 1000;thì không.
ex nihilo

51

Để dễ đọc.

Đặt dấu phẩy và khoảng trắng giữa các số 0 ( 1 000 000 000hoặc 1,000,000,000) sẽ tạo ra lỗi cú pháp và việc có 1000000000mã khiến bạn khó có thể biết chính xác có bao nhiêu số không.

1000*1000*1000làm cho nó rõ ràng là 10 ^ 9, bởi vì mắt chúng ta có thể xử lý các khối dễ dàng hơn. Ngoài ra, không có chi phí thời gian chạy, bởi vì trình biên dịch sẽ thay thế nó bằng hằng số 1000000000.


5
FYI, có một khái niệm về dấu tách chữ số mà tôi đã tìm hiểu gần đây. Java đã có nó được một thời gian và C # 7.0 có thể có được nó. Tôi ước tất cả các ngôn ngữ sẽ có tính năng bắt mắt này. :)
i lovcsharp

1
Tùy thuộc vào ngữ cảnh sử dụng 1,000,000,000sẽ không tạo ra lỗi cú pháp, nó sẽ chỉ có ý nghĩa khác. Ví dụCMTimeMakeWithSeconds( newDurationSeconds, 1,000,000,000 )
Ross Ridge

2
@ JMS10 C # đã có sẵn nếu bạn cài đặt phiên bản xem trước VS15, có thể được viết là1_000_000_000
user1306322

2
Python cũng sẽ trở _thành dấu phân cách :)
Wayne Werner

2
Và C ++ gần đây đã có 'dấu phân cách, trong C ++ 14, vì vậy bạn có thể sử dụng 1'000'000'000. (Nó được chọn vì 1,000,000,000có thể bị hiểu sai là toán tử dấu phẩy hoặc 4 tham số riêng biệt và _1_000_000_000là tên biến hợp lệ (nhưng có thể xấu).)
Justin Time - Phục hồi Monica

27

Để dễ đọc. Để so sánh, Java hỗ trợ _về số lượng để cải thiện khả năng đọc (lần đầu tiên được đề xuất bởi Stephen Colebourne như là một câu trả lời cho Derek Fosterer PROPOSAL: Binary Literals for Project Coin / JSR 334). Một người sẽ viết 1_000_000_000ở đây.

Theo thứ tự thời gian đại khái, từ hỗ trợ cũ nhất đến mới nhất:

Đây là một tính năng tương đối mới để các ngôn ngữ nhận ra rằng chúng phải hỗ trợ (và sau đó là Perl). Như trong câu trả lời xuất sắc của chux @, 1000*1000...là một giải pháp một phần nhưng mở ra cho các lập trình viên các lỗi từ việc tràn bội số ngay cả khi kết quả cuối cùng là một loại lớn.


Nhiều ngôn ngữ lập trình hiện đại có cùng, ví dụ Swift. Không có gì mới.
Sulthan

AFAIK, điều này đến từ Perl. PL / M sử dụng $ cho cùng một mục đích, ví dụ: 0100 $ 0010B
ninjalj

1
khá mới, mặc dù. Tính năng Java có lẽ là 5 năm. Hầu hết các ngôn ngữ khác hỗ trợ cú pháp này đều khá mới - bản thân Swift chỉ mới vài năm. Python bổ sung hỗ trợ trong 3.6, chưa được phát hành.
johncip

2
Ada đã hỗ trợ gạch chân bằng chữ nguyên trong 33 năm nay.
Peter - Tái lập Monica

1
@djechlin: Tôi đã tự do thêm thông tin, đại khái theo thứ tự thời gian. Tôi đã nhầm lẫn trước đây, đánh giá theo chủ đề Project Coin, Stephen Colebourne có lẽ đã lấy ý tưởng gạch dưới bằng chữ nguyên từ Fandom và / hoặc Ruby. Ruby có lẽ đã lấy ý tưởng từ Perl và Perl từ Ada.
ninjalj

7

Có thể đơn giản hơn để đọc và nhận được một số liên kết với các 1,000,000,000hình thức.

Từ khía cạnh kỹ thuật tôi đoán không có sự khác biệt giữa số trực tiếp hoặc phép nhân. Trình biên dịch sẽ tạo ra nó dưới dạng số tỷ không đổi.

Nếu bạn nói về object-c, thì 1000^3sẽ không hoạt động vì không có cú pháp như vậy cho pow (đó là xor). Thay vào đó, pow()chức năng có thể được sử dụng. Nhưng trong trường hợp đó, nó sẽ không tối ưu, nó sẽ là một hàm gọi thời gian chạy không phải là trình biên dịch được tạo.


3

Để minh họa các lý do hãy xem xét chương trình thử nghiệm sau:

$ 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 Tôi không khuyên bạn nên học một ngôn ngữ bằng cách đọc các bài viết trên Wikipedia.
Peter - Tái lập Monica

0

Một cách khác để đạt được hiệu ứng tương tự trong C đối với các số thập phân là sử dụng ký hiệu dấu phẩy động theo nghĩa đen - miễn là gấp đôi có thể đại diện cho số bạn muốn mà không mất độ chính xác.

IEEE 754 64 bit có thể biểu thị bất kỳ số nguyên không âm nào <= 2 ^ 53 mà không gặp vấn đề gì. Thông thường, gấp đôi dài (80 hoặc 128 bit) có thể đi xa hơn thế. Việc chuyển đổi sẽ được thực hiện vào thời gian biên dịch, do đó không có chi phí thời gian chạy và bạn có thể sẽ nhận được cảnh báo nếu có sự mất chính xác không mong muốn và bạn có một trình biên dịch tốt.

long lots_of_secs = 1e9;
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.