39

In languages that don't allow underscores in integer literals, is it a good idea to create a constant for 1 billion? e.g. in C++:

size_t ONE_BILLION = 1000000000;

Certainly, we shouldn't create constants for small numbers like 100. But with 9 zeros, it's arguably easy to leave off a zero or add an extra one in code like this:

tv_sec = timeInNanosec / 1000000000;
tv_nsec = timeInNanosec % 1000000000;
Kilian Foth
  • 109,273
Martin C. Martin
  • 1,223
  • 1
  • 9
  • 9
  • 25
    I hope everyone here votes for NO. That way, maybe one day my bank will transfer one billion dollars to my account because a programmer didn't use a constant and misplaced a zero! :) – Reactgular May 24 '13 at 16:30
  • 43
    Why not create constants for small numbers? What does 100 mean? Unless there is some context, it's a magic number. – Allan May 24 '13 at 16:30
  • 1
    How long will it take you to figure out what's going on when a disgruntled dev changes the value of ONE_BILLION to 1000000000.01? Hello Office Space. – MrFox May 24 '13 at 16:50
  • 3
    @MrFox ssshhhhhhhhh .... I'm hacking the banks source code to make that change. – Reactgular May 24 '13 at 17:19
  • 4
    @MathewFoscarini In general, mistakes can go either way. But when it comes to your bank, mistakes will always go against you. – emory May 24 '13 at 18:30
  • 23
    Consider writing 1e9, 10^9 or 1_000_000_000 if the language you are using supports it. – hammar May 24 '13 at 18:58
  • 1
    I like JohnB's proposed answer, but I think it better to leave it as ONE_BILLION with a comment as "//nanaseconds per second", otherwise it looks like your comment is frivolous and came from an idiot. –  May 24 '13 at 20:27
  • 2
    you might also add a L suffix so it become a long and you don't get bitten by integer overflow – ratchet freak May 24 '13 at 23:27
  • I've had various people tell me that it's PROBABLY best to use no numbers in your code whatsoever (possibly excepting 1 and 0 which make nice loop terminations). I don't know if they really believed it, but it might be an interesting experiment. – Bill K May 25 '13 at 07:37
  • @MrFox: Considering that size_t is not going to accept double literals, not very long. – Joren May 25 '13 at 16:16
  • 6
  • How about 'tv_nsec = timeInNanosec - tv_sec'? – JBRWilkinson May 26 '13 at 17:21
  • 1
    As another comment, size_t is supposed to be a variable able to contain the size of an item in bytes. Which is certainly not the case here so this should not be a size_t – JohnB May 26 '13 at 18:19
  • I'm trying to think of a language that does allow _ in integer constants. Can anyone name some of those? – boatcoder May 30 '13 at 18:48
  • C, C++, Python, Java before 7. So, most of the popular languages. – Martin C. Martin Jun 01 '13 at 18:16
  • @Mark0978: Ada, Perl. – Keith Thompson Jun 03 '13 at 19:33
  • 1
    @MartinC.Martin: Those are languages that don't allow _ in integer constants. – Keith Thompson Jun 03 '13 at 19:33
  • @ratchetfreak: In C and C++, the L suffix is unnecessary; an integer constant is automatically of a type big enough to hold it. On the other hand, an expression like 1000 * 1000 * 1000 can overflow, since 1000 is of type int. – Keith Thompson Jun 03 '13 at 19:35
  • @mark newest java, D – ratchet freak Jun 03 '13 at 20:58
  • @MartinC.Martin While C++ does allow for underscores in numeric literals you can split up large (or complex literals) using the token pasting operator##, ie: #define ONE_BILLION 1 ## 000 ## 000 ## 000. Less readable than underscores, but it does arguably simplify visual verification. – Marc Butler Feb 28 '15 at 04:59

13 Answers13

146

Create one called NANOSECONDS_IN_ONE_SECOND instead as that what it represents.

Or a shorter, better name if you can think of one.

JohnB
  • 1,251
  • 2
  • 8
  • 10
  • 58
    I'd say Nanoseconds_Per_Second but this is, in my opinion, the correct answer. – KChaloux May 24 '13 at 16:56
  • 8
    @Mathew I don't get your point. There's nothing wrong with saying millimeters per meter. You may be implying that it is redundant, in that nanosecond MEANS one billion fractions of a second, but there's nothing wrong in stating it again. It's like saying 1 + 1 = 2. "x per y" continues to make more sense when x and y are disjoint, like "units per half dozen" or "nanoseconds per millisecond" – Mark Canlas May 24 '13 at 17:34
  • 7
    @MathewFoscarini Actually, no, in this context it's not. If it were, a constant named NANOSECONDS is meaningless as you can't tell what it's supposed to apply to. Likewise, NANOSECONDS_PER_MICROSECOND is a similar valid constant that makes sense. – Izkata May 24 '13 at 17:41
  • How can you have NANOSECONDS_PER_MICROSECOND? That's like saying KILOMETERS PER MILE. I must not be understanding the term correctly. – Reactgular May 24 '13 at 17:43
  • 3
    oh! I get it. Sorry. KILOMETERS_PER_MILE = 1.60934 – Reactgular May 24 '13 at 17:44
  • 1
    I think what Mathew was trying to say is that traditionally we use per to describe units of one type in units of another type, such as miles per hour. The confusions was why we would use per to describe units of one type in units of the same type. Subtle difference in the meaning of per is all. – Frank B May 24 '13 at 19:27
  • 5
    @MathewFoscarini, "millimeters per meter" is a way to remove the unit on the conversion to get the raw value. 1mm/1m = 1000, which is exactly the point of what's being done here. – zzzzBov May 24 '13 at 19:48
  • 3
    I like x_PER_y as it is analogous to x/y and makes dimensional analysis easier. For example, when you see something like NANOSEC_PER_DAY = NANOSEC_PER_SEC * SEC_PER_MIN * MIN_PER_HOUR * HOURS_PER_DAY, it is easy to verify that the units on "top" and "bottom" cancel one another out. – Kristopher Johnson May 24 '13 at 21:00
  • 12
    Why so much typing? NS_PER_SEC should be obvious to anyone who ought to be dealing with nanoseconds. – Rex Kerr May 24 '13 at 21:03
  • 1
    @FumbleFingers I agree, his answer is better as it explains why. Vote for his, not mine, – JohnB May 25 '13 at 07:36
  • 1
    @FumbleFingers Why would you downvote this answer? Do you find it's wrong? I think it's prefectly valid as it hits the point in that you should name constants as per their meaning, not just for their value. I, for once, upvoted both (upvotes are free, you know). – Nadir Sampaoli May 25 '13 at 11:06
  • @Nadir: I was visited by the insidious Jack Daniel last night. I apologise to JohnB for the gratuitously inflammatory comment, which I've deleted. But I still prefer the other answer. – FumbleFingers May 25 '13 at 16:29
  • @RexKerr: Fine here, but that pattern would cause a conflict for µs and ms: both are MS_PER_SEC when capitalised. Personally I might just use constants like NANO, MICRO, MILLI because whether you're talking about seconds or meters or teslas isn't relevant. – Joren May 25 '13 at 16:33
  • 1
    @Joren, my experience has been the people tend to use US to indicate microseconds, for the purposes of constants. It's unambiguous when used in a context where the constant represents some sort of measurement. – Dancrumb May 25 '13 at 17:20
  • @Joren - Using anything other than unicode Mu or Latin u/U for micro is asking for confusion. Also, is NANO 1e9 or 1e-9? Can't really tell...so you can't just do that. – Rex Kerr May 25 '13 at 17:42
  • @RexKerr If you use NANO for anything other than 1e-9, you likely have other problems as well... now, NANOSECONDS_PER_SECOND would definitely be 1e9. – user May 26 '13 at 14:08
  • @MichaelKjörling - I agree, but Joren was proposing to use it for 1e9 (to mean NS_PER_SEC). And if he is proposing that for NANO I can't trust what NANO means as a constant. – Rex Kerr May 26 '13 at 16:03
  • @RexKerr: "Using anything other than unicode Mu or Latin u/U for micro is asking for confusion." - Yes that's exactly my point? – Joren May 26 '13 at 20:09
  • @RexKerr: I most certainly wasn't proposing to define NANO = 1e9. Obviously a nano-anything is 1e-9. – Joren May 26 '13 at 20:09
  • Is it? There are no basis units smaller ? (Hint: Plank's time) There is no indication of point of view or context with nano by itself. Coupled with a _PER_SECOND or _PER_MICROSECOND or any other basis the purpose of the coefficient becomes clear. Without it, confusion or assumption. Some assumptions are safer than others, but still.. – JustinC May 26 '13 at 23:35
  • @RexKerr NS_PER_SEC is not even consistent with itself. NS_PER_S maybe? More time is spent reading code than writing it. I feel that you should code for ease of reading, not typing. Most IDE's will lend themselves to making NANOSECONDS_PER_SECOND only a few keystrokes anyway. – Chris Kent May 31 '13 at 15:07
  • Watch out for #define NANOSECONDS_PER_SECOND 100000000. (Hint: count the zeros.) – Keith Thompson Jun 03 '13 at 19:39
68

Constants are meant to give numbers meaning. There is not any additional meaning in ONE_BILLION to 1000000000. Actually, it makes it more confusing, because in different natural languages, a billion means something different (either a thousand million or a million million)! If you want to write it shorter, there's a good chance your programming language allows the use scientific notation, i.e. 1e9. Otherwise, I agree with @JohnB, that this number really means the number of nanoseconds in a second, so name it that.

Thijs van Dien
  • 1,071
  • 1
  • 7
  • 13
  • 10
    Good pointing that billion in different languages mean different amount of zeros. – frozenkoi May 24 '13 at 22:46
  • 3
    would suggest changing regular languages to natural languages. regular means something else... – jk. May 25 '13 at 06:39
  • Different interpretations of "billion" in languages such a good point! Why can't I upvote your answer twice! – Force444 May 25 '13 at 13:10
  • 3
    You don't need different languages. You don't even need different countries. In British English, "billion" means something different before and after 1974 in official communications (mass media and government), and both usages still exist. – Jörg W Mittag May 26 '13 at 11:26
  • 1
    "There is not any additional meaning in ONE_BILLION to 10000000000.. I disagree. (Hint: I deliberately misquoted you and added another zero; would have have noticed if I hadn't mentioned it?) – Keith Thompson Jun 03 '13 at 19:41
34

Most languages feature some kind of exponential notation. A million is 1e6, (meaning 1 times 10 to the power of 6). This basically solves the issue even better than most propositions here.

In a lot of C-like languages, the scientific notation is however defining a floating point type, which is unfortunate if you really need an int. However, you can easily type-cast that constant to avoid implicit conversions in your formular.

n / int(1e9) would divide by a billion.

In your example, dealing with physical quantities (time in nanosecond), I would generally ask myself whether integer is the right type. In fact a floating point double might be better suited when dealing with measurable quantities (although there are of course cases where you would prefer a long long).

Mmmh mmh
  • 103
wirrbel
  • 3,028
  • 6
    I think the NANOSECONDS_IN_ONE_SECOND solution is much clearer and neater – Andreas Bonini May 25 '13 at 17:40
  • 1
    The Question was about integer liberals and I propose to use scientific notation. Whether to do this in place or by defining a constant is an issue of structuring code that was not asked for in the question. Defining a constant adds limited abstraction, I would write a conversion function/macro to achieve better abstraction – wirrbel May 25 '13 at 18:00
  • 1
    would casting a very large double to an int not risk the typical rounding difference problems of floating point numbers? – Philipp May 26 '13 at 12:11
  • with normal precision integer types this shouldnot be a problem as long as you use a double precision float to convert from. you are right when using values of the long long range. – wirrbel May 26 '13 at 12:50
27

For one or two usages, I would use the convention:

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

It's perfectly self explanatory, gets compiled to a constant and it's hard to screw up.

Also, it's very useful in cases such as:

var Time = 24 * 60 * 60;

where it's easy to see we are talking about one day in seconds.

Sklivvz
  • 5,260
10

The length of the value is not what defines whether a constant is needed or not.

You use constants to avoid magic numbers, not to avoid typing.

For example these are perfectly valid constants:

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;

Use:

public static final int NANOSECS_PER_SECOND = 1000000000;

(code samples are in Java, translate to your favorite language )

gnat
  • 21,213
  • 29
  • 113
  • 291
8

An American or European billion?

(or in technical terms, a billion in the short scale or long scale - one is 1000 million, the other is a million million).

Given this confusion, then I'd say yes - it makes sense to define it once and keep with it, likewise applies to any constant you need to agree the definition on - define it once.

gbjbaanb
  • 48,585
  • 6
  • 103
  • 173
5

Reasons Not To

Firstly, here is a reason not write any underscores or use any trick to simulate it: it makes the constants harder to find in the code. Suppose that some program exhibits, somewhere in its operation, hard-coded value 1500000 for some parameter. I want to know where in the source code of the program this actually occurs, so I grep the code for 1500000, and find nothing. Why? Might it be in hexadecimal (but why for such a round decimal number). Unbeknownst to me, the constant is actually written as 1_500_000. I needed the regex 1_?500_?000.

Guiding Characters in Comment

Just because one kind of visual aid is not available, or we don't wish to use it for the above reason, doesn't mean that we cannot take advantage of the two dimensions of the text file to create an alternative visual aid:

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

With this we can easily convince ourselves that there are three groups of three zeros. Yet, we can still grep the source code for 1000000000 and find it.

Syntax Coloring

A text editor with programmable syntax coloring can be made to color groups digits in numeric constants with alternating colors for better readability. We don't have to do anything in the code.

Preprocessing: C, C++, Objective C

Now, if we really want some commas between digits, in C and C++ we can use some 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)

Works for numbers like TH(1,234,567,890).

A macro similar to TH can also work with token pasting rather than arithmetic. In the C preprocessor, the binary ## operator ("token paste") can be used in a macro body in order to paste together two operands into a single token. One or both of the operands can be macro arguments. The downside here (creating a risk for us) is that if the resulting catenation isn't a valid token, the behavior is undefined.

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

Now

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 programs that paste together identifiers and use the results to name global variables and functions exist and are awful to work with because they are impervious to tools like GNU id-utils and ctags.

Kaz
  • 3,612
  • 1
  • 19
  • 30
  • 2
    +1 for one of the best abuses of the preprocessor I've seen. I'd still go with NSEC_PER_SEC or something in production, though. – Victor May 25 '13 at 16:34
  • Very nearly -1 for abusing the preprocessor :) – user May 26 '13 at 14:11
3

Yeah, that sounds like a reasonable idea. Off-by-one DIGIT errors are even worse than the infamous off-by-one errors. Although, it may create confusion for other people (including your future self) to read the code.

A more explanatory name like NANOSEC_PER_SEC seems good, as it would add clarity where it is used for time. However, it makes no sense to use in contexts other than time, and it would be impractical to create a separate 1,000,000,000 for every situation.

What you really want to do, silly as it seems at first, is 'divide over sec'. This leaves NANO_PER, which is not only language-independent (10^9 in America and Europe) but also situation-independent (no limiting on the units), and it is easy to type and read.

MegaWidget
  • 131
  • 3
  • this post is rather hard to read (wall of text). Would you mind [edit]ing it into a better shape? – gnat May 24 '13 at 21:12
3

In general it's a bad idea to use scalar constants for unit conversions, and if you find yourself making constants for such things you're doing conversion in way too many places.

When you have a quantity of one unit (say, 10 seconds), and want to convert to another unit (i.e. nanoseconds); this is precisely the time to use the type system of your language to ensure that the units are actually scaled as you intend.

Make your function take a Nanoseconds parameter, and provide conversion operators and/or constructors in that class for Seconds, Minutes, or what-have-you. This is where your const int or #define or 1e9 seen in other answers belongs.

This avoids having variables of ambiguous units floating around your code; and prevents entire swathes of bugs from where the wrong multiply/divide was applied, or was already applied, or the quantity was actually distance instead of time, or...

Also, in such classes it's good to make construction from plain scalarsprivate and use a static "MakeSeconds(int)" or similar to discourage sloppy use of opaque numbers.

More specifically to your example, in C++ check out Boost.Chrono.

rvalue
  • 294
  • 1
  • At the very least, use a common type with a scaling or offset factor from a basis, much like the often maligned timezone.
  • – JustinC May 26 '13 at 08:50