ทำไมเขียน 1,000,000,000 เป็น 1,000 * 1,000 * 1,000 ใน C


142

ในรหัสที่สร้างโดย Apple มีบรรทัดนี้:

CMTimeMakeWithSeconds( newDurationSeconds, 1000*1000*1000 )

มีเหตุผลใดที่จะแสดง1,000,000,000เป็น1000*1000*1000?

ทำไมไม่1000^3ทำอย่างนั้นล่ะ


45
ความชัดเจนและการอ่านรหัสได้ คุณไม่สามารถใส่หรือ 'เป็นตัวคั่นใน C ดังนั้นสิ่งที่ดีที่สุดถัดไปคือการคำนวณค่าจากการคูณ ^ เป็นโอเปอเรเตอร์ที่ไม่เกี่ยวข้องใน C - เอกสิทธิ์ OR
Iwillnotexist Idonotexist

54
โดยเฉพาะอย่างยิ่งใช้สำหรับช่วงเวลาที่ชอบ: 2 * 60 * 60 .. มันง่ายที่จะสังเกตเห็นว่าเป็นเวลา 2 ชั่วโมง ..
Idali

53
สำหรับหนึ่งฉันสงสัยว่า 1,000,000,000 ไม่ได้เป็นไวยากรณ์ที่ถูกต้อง
paparazzo

15
1_000_000_000โดยวิธีการเขียนโปรแกรมภาษาที่ทันสมัยมีทางเลือกที่จะเขียนเหมือนกันเช่นในสวิฟท์ อย่างไรก็ตามด้วยค่าคงที่เวลานี่เป็นเรื่องยากมากขึ้น มันอ่านได้มากขึ้นในการเขียน30 * 60(30 นาทีวินาที) 1800มากกว่าที่จะเขียน มีภาษาที่จะช่วยให้คุณเขียนหน่วยเช่นmetersช่วยให้คุณป้องกันตัวเองจากการมอบหมายที่ไม่ดี
Sulthan

29
^เป็น XOR ไม่ใช่ตัวดำเนินการเลขชี้กำลังหรือกำลังไฟฟ้า
3

คำตอบ:


200

เหตุผลหนึ่งในการประกาศค่าคงที่ด้วยวิธีคูณคือการปรับปรุงความสามารถในการอ่านในขณะที่ประสิทธิภาพของรันไทม์ไม่ได้รับผลกระทบ นอกจากนี้เพื่อระบุว่าผู้เขียนกำลังคิดแบบทวีคูณเกี่ยวกับจำนวน

พิจารณาสิ่งนี้:

double memoryBytes = 1024 * 1024 * 1024;

มันชัดเจนดีกว่า:

double memoryBytes = 1073741824;

เมื่อมองไม่เห็นแวบแรกกำลังที่สามของ 1024

ในฐานะที่เป็นอามิน Negm-Awad กล่าวถึงผู้ประกอบการเป็นไบนารี^ XORหลายภาษาขาดตัวดำเนินการการยกกำลังในเวลาและการคอมไพล์ในตัวดังนั้นการคูณ


13
และในภาษาที่มีตัวดำเนินการการยกกำลังนั้นก็ไม่จำเป็นว่า '^' ยกตัวอย่างเช่นใน Fortran มันคือ '**'
jamesqf

4
คุณควรรวมลิงค์ที่ชี้ไปยังข้อแม้ที่สำคัญซึ่งให้ไว้ในคำตอบด้านล่างจาก @chux: stackoverflow.com/a/40637622/1841533 (โดยเฉพาะอย่างยิ่งในชื่อ OP ที่ติดแท็ก "c" ซึ่งมีความเสี่ยงสูงต่อมือนี้ การดำเนินการด้านข้างดูเหมือนจะมีเงื่อนไขทั้งหมดที่ จำกัด ไว้ที่ประเภทที่เล็กกว่าและดังนั้นการคูณอาจล้นปัญหา ') securecoding.cert.org/confluence/display/c/…อาจช่วยหลีกเลี่ยงสิ่งเหล่านั้นในกรณีทั่วไปได้หรือไม่
Olivier Dulac

4
นอกจากนี้เราควรทราบว่าการคำนวณเสร็จสิ้นในเวลารวบรวม มาตรฐาน C ต้องการการนำไปใช้เพื่อให้สามารถคำนวณนิพจน์คงที่ในเวลารวบรวมสำหรับคุณลักษณะต่าง ๆ ของภาษาและเราสามารถสรุปได้อย่างปลอดภัยว่าเป็นจริงเมื่อมีการใช้นิพจน์คงที่เช่นในตัวอย่างนี้
ouah

13
เก็บจำนวนหน่วยความจำเป็นสองเท่าหรือไม่? ดูเหมือนว่าอาจเป็นแหล่งที่มาของข้อผิดพลาด
JAB

7
@supercat ฉันรู้ว่า แต่โดยการใช้สองครั้งคุณอาจมีกรณีที่พูดว่าคุณต้องการเป็นส่วนหนึ่งของช่วงหน่วยความจำคุณหารด้วยxเพื่อให้ได้ขนาดของช่วงย่อย ... และทันใดนั้นคุณมีเศษส่วน ไบต์ซึ่งอาจต้องใช้ตรรกะเพิ่มเติมเพื่อชดเชย
JAB

73

ทำไม1000^3ล่ะ

ผลลัพธ์ของ1000^3คือ 1003 ^เป็นตัวดำเนินการ bit-XOR

แม้ว่ามันจะไม่ได้จัดการกับ Q แต่ฉันก็เพิ่มการชี้แจง x^yไม่ได้ประเมินเสมอไปx+yเช่นเดียวกับในตัวอย่างของผู้ถาม คุณต้อง xor ทุก ๆ ในกรณีของตัวอย่าง:

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

แต่

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

3
ครับผมไม่ชัดเจนว่า 1,003 ^ 3 เป็น 1003 อย่างไร Google และ Mac Calculator แสดง 1,000 ^ 3 = 1,000,000,000 คุณสามารถอธิบาย?
Mahesh

57
^แฮคเกอร์ผู้ประกอบการหมายถึงใน C / C ++ / Objective-C ฯลฯ ในเครื่องคิดเลขก็มักจะหมายถึง x-to-Y อำนาจ
Tamás Zahola

5
อืมบิตของ 1,000 และ 3 ไม่ทับซ้อนกัน ลักษณะนี้จึงไม่ถูกต้อง
Yakk - Adam Nevraumont

19
บิตทับซ้อนกัน แต่ไม่ใช่ของ 1 : -]
Amin Negm-Awad

6
@Yakk: แน่นอนมันดูผิดมาก! ... ฉันหวังว่าหลายคนจะไม่คิดว่า "A ^ B" มอบ A + B เสมอ (แต่ฉันกลัวว่าจะมีบางอย่าง ... )
Olivier Dulac

71

โดยมีสาเหตุไม่ได้1000 * 1000 * 1000ใช้

ด้วย 16-bit int, 1000 * 1000overflows ดังนั้นการใช้1000 * 1000 * 1000จะช่วยลดการพกพา

ด้วย 32- บิตintบรรทัดแรกของรหัสล้นต่อไปนี้

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

แนะนำว่าค่านำที่ตรงกับประเภทของปลายทางสำหรับการอ่านการพกพาและความถูกต้อง

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

ยังสามารถใช้ง่ายสัญกรณ์สำหรับค่าที่ว่าซึ่งแสดงเป็นe doubleแน่นอนว่าสิ่งนี้นำไปสู่การรู้ว่าdoubleสามารถแสดงค่าตัวเลขทั้งหมดได้หรือไม่ - สิ่งที่น่ากังวลกับค่าที่มากกว่า 1e9 (ดูDBL_EPSILONและDBL_DIG)

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

5
คำพูดที่สำคัญมาก! securecoding.cert.org/confluence/display/c/…อาจช่วยได้มากในหลายกรณี?
Olivier Dulac

2
A doubleสามารถแทนจำนวนเต็มทั้งหมดได้สูงสุด 2 ^ 53 ≈ 9e15
Edgar Bonet

3
@EdgarBonet True ที่binary64สามารถแสดงจำนวนเต็มได้ทั้งหมดประมาณ 9e15 แต่ C ไม่ได้ระบุการdoubleใช้งานของ binary64 แม้ว่ามันจะใช้กันอย่างแพร่หลาย ตามข้อมูลจำเพาะ C ค่าสูงสุดถึง 1e9 หรือมากกว่านั้นจะสามารถแทนได้อย่างแน่นอน มันขึ้นอยู่กับว่าคุณต้องการโค้ดเพื่อระบุหรือพึ่งพาการปฏิบัติทั่วไป
chux - Reinstate Monica

4
@ แพทริกทั้งสอง1000และ1000000000000เป็นจำนวนเต็มคงที่ แต่ละอิสระกับการมีประเภทที่เลือกจากint, หรือlong long longคอมไพเลอร์ใช้ชนิดแรกของ 3 ตัวที่ค่าคงที่จำนวนเต็มพอดี 1000 * 1000 * 1000 * 1000จะทำกับintคณิตศาสตร์เป็นแต่ละใน1000 intสินค้าล้นกับ int32 1000000000000 เป็นตัวแทนแน่นอนlong long(หรืออาจแคบกว่า) - ไม่มีล้น ประเภทของเป้าหมายlong long Durationไม่มีผลต่อ "ด้านขวาของการถอดความ ="
chux - Reinstate Monica

2
การวางประเภทที่กว้างขึ้นก่อนในการคูณเป็นสิ่งสำคัญ กับ 16 บิตint, long x = 1000 * 1000 * 1000L;จะล้นในขณะที่long x = 1000L * 1000 * 1000;จะไม่
อดีตนิฮอโล

51

สำหรับการอ่าน

การวางเครื่องหมายจุลภาคและช่องว่างระหว่างศูนย์ ( 1 000 000 000หรือ1,000,000,000) จะทำให้เกิดข้อผิดพลาดทางไวยากรณ์และการมี1000000000รหัสทำให้ยากที่จะเห็นจำนวนศูนย์ที่มี

1000*1000*1000ทำให้เห็นได้ชัดว่ามันคือ 10 ^ 9 เพราะดวงตาของเราสามารถประมวลผลชิ้นได้ง่ายขึ้น 1000000000นอกจากนี้ไม่มีค่าใช้จ่ายรันไทม์เพราะคอมไพเลอร์จะแทนที่ด้วยอย่างต่อเนื่อง


5
FYI มีแนวคิดของตัวคั่นหลักที่ฉันเรียนรู้เมื่อเร็ว ๆ นี้ Java มีมาระยะหนึ่งแล้วและ C # 7.0 อาจได้รับ ฉันหวังว่าทุกภาษาจะมีคุณสมบัติที่น่าสนใจนี้ :)
iheartcsharp

1
ทั้งนี้ขึ้นอยู่กับบริบทที่ใช้1,000,000,000จะไม่ทำให้เกิดข้อผิดพลาดทางไวยากรณ์มันจะหมายถึงอย่างอื่น ตัวอย่างเช่นCMTimeMakeWithSeconds( newDurationSeconds, 1,000,000,000 )
Ross Ridge

2
@ JMS10 C # มีอยู่แล้วถ้าคุณติดตั้งเวอร์ชั่นตัวอย่าง VS15 สามารถเขียนเป็น1_000_000_000
user1306322

2
งูหลามจะได้รับ_เป็นตัวคั่นด้วย :)
เวย์นเวอร์เนอร์

2
และ C ++ เมื่อเร็ว ๆ นี้มี'คั่นใน C ++ 14 1'000'000'000เพื่อให้คุณสามารถใช้ (มันเป็นทางเลือกเพราะ1,000,000,000อาจถูกตีความผิดเป็นผู้ประกอบการจุลภาคหรือ 4 พารามิเตอร์ที่แตกต่างกันและ_1_000_000_000มีผลบังคับใช้ ( แต่อาจจะไม่ดี) ชื่อตัวแปร.)
จัสตินเวลา - คืนสิทธิ์ให้กับโมนิกา

27

สำหรับการอ่าน สำหรับการเปรียบเทียบ Java สนับสนุน_ตัวเลขเพื่อปรับปรุงความสามารถในการอ่าน (เสนอครั้งแรกโดย Stephen Colebourne เพื่อตอบกลับข้อเสนอของ Derek Foster: Binary Literalsสำหรับ Project Coin / JSR 334) หนึ่งจะเขียน1_000_000_000ที่นี่

ตามลำดับเวลาจากการสนับสนุนที่เก่าแก่ที่สุดไปจนถึงใหม่ล่าสุด:

มันเป็นคุณสมบัติที่ค่อนข้างใหม่สำหรับภาษาที่จะรู้ว่าพวกเขาควรจะสนับสนุน (แล้วมี Perl) เช่นเดียวกับคำตอบที่ยอดเยี่ยมของ chux @ เป็นคำตอบ1000*1000...บางส่วน แต่เปิดโปรแกรมเมอร์จนถึงข้อบกพร่องจากการคูณทวีคูณแม้ว่าผลลัพธ์สุดท้ายจะเป็นประเภทใหญ่


ภาษาโปรแกรมสมัยใหม่จำนวนมากมีเหมือนกันเช่น Swift ไม่มีอะไรใหม่.
Sulthan

AFAIK สิ่งนี้มาจาก Perl PL / M ใช้ $ เพื่อจุดประสงค์เดียวกันเช่น: 0100 $ 0010B
ninjalj

1
มันเป็นค่อนข้างใหม่ แต่ คุณสมบัติ Java อาจจะอายุ 5 ปี ภาษาอื่น ๆ ส่วนใหญ่ที่สนับสนุนไวยากรณ์นี้ค่อนข้างใหม่ - สวิฟท์เองนั้นมีอายุเพียงไม่กี่ปี Python เพิ่มการสนับสนุนใน 3.6 ซึ่งยังไม่ได้เปิดตัว
johncip

2
Ada สนับสนุนขีดเส้นใต้เป็นตัวอักษรจำนวนเต็มเป็นเวลา 33 ปีแล้ว
ปีเตอร์ - Reinstate Monica

1
@djechlin: ฉันมีเสรีภาพในการเพิ่มข้อมูลเพิ่มเติมโดยประมาณตามลำดับเวลา ฉันถูกเข้าใจผิดมาก่อนโดยตัดสินจากเธรด Project Coin สตีเฟ่นโคลบอร์นอาจใช้ความคิดในการขีดเส้นใต้ตัวอักษรจำนวนเต็มจาก Fandom และ / หรือทับทิม Ruby อาจใช้แนวคิดจาก Perl และ Perl จาก Ada
ninjalj

7

อาจจะง่ายกว่าในการอ่านและรับความสัมพันธ์บางอย่างกับ1,000,000,000แบบฟอร์ม

จากด้านเทคนิคฉันคิดว่าไม่มีความแตกต่างระหว่างจำนวนโดยตรงหรือการคูณ คอมไพเลอร์จะสร้างมันเป็นค่าคงที่จำนวนพันล้านอยู่ดี

หากคุณพูดเกี่ยวกับวัตถุประสงค์ -c แล้ว1000^3จะไม่ทำงานเพราะไม่มีไวยากรณ์ดังกล่าวสำหรับ pow (มันเป็น xor) pow()สามารถใช้ฟังก์ชันแทนได้ แต่ในกรณีนั้นมันจะไม่เหมาะสมที่สุดมันจะเป็นการเรียกใช้ฟังก์ชัน runtime ไม่ใช่คอมไพเลอร์ที่สร้างค่าคงที่


3

เพื่อแสดงเหตุผลให้พิจารณาโปรแกรมทดสอบต่อไปนี้:

$ 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 ฉันจะไม่แนะนำให้เรียนรู้ภาษาโดยการอ่านบทความ Wikipedia
Peter - Reinstate Monica

0

อีกวิธีหนึ่งในการทำให้เอฟเฟ็กต์ที่คล้ายกันใน C สำหรับตัวเลขทศนิยมคือการใช้สัญกรณ์จุดลอยตัวตามตัวอักษร - ตราบใดที่ double สามารถแสดงตัวเลขที่คุณต้องการโดยไม่สูญเสียความแม่นยำ

IEEE 754 64- บิตคู่สามารถแสดงจำนวนเต็มใด ๆ ที่ไม่เป็นลบ <= 2 ^ 53 โดยไม่มีปัญหา โดยปกติแล้ว double long (80 หรือ 128 bits) สามารถไปได้ไกลกว่านั้น การแปลงจะทำในเวลาคอมไพล์ดังนั้นจึงไม่มีค่าใช้จ่ายในการดำเนินการและคุณอาจได้รับคำเตือนหากมีการสูญเสียความแม่นยำอย่างไม่คาดคิดและคุณมีคอมไพเลอร์ที่ดี

long lots_of_secs = 1e9;
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.