Before we talk about our next subject, we’re going to sidebar into the topic of scientific notation.

**Scientific notation** is a useful shorthand for writing lengthy numbers in a concise manner. And although scientific notation may seem foreign at first, understanding scientific notation will help you understand how floating point numbers work, and more importantly, what their limitations are.

Numbers in scientific notation take the following form: *significand* x 10^{exponent}. For example, in the scientific notation `1.2 x 10`

, ^{4}`1.2`

is the significand and `4`

is the exponent. Since 10^{4} evaluates to 10,000, 1.2 x 10^{4} evaluates to 12,000.

By convention, numbers in scientific notation are written with one digit before the decimal point, and the rest of the digits afterward.

Consider the mass of the Earth. In decimal notation, we’d write this as `5973600000000000000000000 kg`

. That’s a really large number (too big to fit even in an 8 byte integer). It’s also hard to read (is that 19 or 20 zeros?). Even with separators (5,973,600,000,000,000,000,000,000) the number is still hard to read.

In scientific notation, this would be written as `5.9736 x 10`

, which is much easier to read. Scientific notation has the added benefit of making it easier to compare the magnitude of two really large or really small numbers simply by comparing the exponent.^{24} kg

Because it can be hard to type or display exponents in C++, we use the letter ‘e’ (or sometimes ‘E’) to represent the “times 10 to the power of” part of the equation. For example, `1.2 x 10`

would be written as ^{4}`1.2e4`

, and `5.9736 x 10`

would be written as ^{24}`5.9736e24`

.

For numbers smaller than 1, the exponent can be negative. The number `5e-2`

is equivalent to `5 * 10`

, which is ^{-2}`5 / 10`

, or ^{2}`0.05`

. The mass of an electron is `9.1093822e-31 kg`

.

How to convert numbers to scientific notation

Use the following procedure:

- Your exponent starts at zero.
- Slide the decimal so there is only one non-zero digit to the left of the decimal.
- Each place you slide the decimal to the left increases the exponent by 1.
- Each place you slide the decimal to the right decreases the exponent by 1.
- Trim off any leading zeros (on the left end of the significand)
- Trim off any trailing zeros (on the right end of the significand) only if the original number had no decimal point. We’re assuming they’re not significant unless otherwise specified.

Here’s some examples:

Start with: 42030 Slide decimal left 4 spaces: 4.2030e4 No leading zeros to trim: 4.2030e4 Trim trailing zeros: 4.203e4 (4 significant digits)

Start with: 0.0078900 Slide decimal right 3 spaces: 0007.8900e-3 Trim leading zeros: 7.8900e-3 Don't trim trailing zeros: 7.8900e-3 (5 significant digits)

Start with: 600.410 Slide decimal left 2 spaces: 6.00410e2 No leading zeros to trim: 6.00410e2 Don't trim trailing zeros: 6.00410e2 (6 significant digits)

Here’s the most important thing to understand: The digits in the significand (the part before the ‘e’) are called the **significant digits**. The number of significant digits defines a number’s **precision**. The more digits in the significand, the more precise a number is.

Precision and trailing zeros after the decimal

Consider the case where we ask two lab assistants each to weigh the same apple. One returns and says the apple weighs 87 grams. The other returns and says the apple weighs 87.00 grams. Let’s assume the weighing is correct. In the former case, the actual weight of the apple could be anywhere between 86.50 and 87.49 grams. Maybe the scale was only precise to the nearest gram. Or maybe our assistant rounded a bit. In the latter case, we are confident about the actual weight of the apple to a much higher degree (it weighs between 86.9950 and 87.0049 grams, which has much less variability).

So in standard scientific notation, we prefer to keep trailing zeros after a decimal point, because those digits impart useful information about the precision of the number.

However, in C++, 87 and 87.000 are treated exactly the same, and the compiler will store the same value for each. There’s no technical reason why we should prefer one over the other (though there might be scientific reasons, if you’re using the source code as documentation).

Now that we’ve covered scientific notation, we’re ready to cover floating point numbers.

Quiz time

Question #1

Convert the following numbers to C++ style scientific notation (using an e to represent the exponent) and determine how many significant digits each has (keep trailing zeros after the decimal):

a) 34.50

b) 0.004000

c) 123.005

d) 146000

e) 146000.001

f) 0.0000000008

g) 34500.0

4.8 -- Floating point numbers |

Index |

4.6 -- Fixed-width integers and size_t |

g) "If the number had been specified as 34500, then the answer would have been 3.45e4."

How is that possible when you have:

Question d): 146000

Answer d): 1.46000e5

"We don’t trim the trailing zeros here because the number does have a decimal point. Even though the decimal point doesn’t affect the value of the number, it affects the precision, so it needs to be included in the significant."

This was written in the answer.

which number are you referring to ? the number with decimal point ?

34500 or 146000 ?

If you have zeros after the decimal point you shouldn't trim them (like 85.00 would be 8.500e1). Otherwise you can, although it's good for documentation to keep them (eg. 8500 = 8.5e3 or 8.500e3).

yep .. also beats the purpose if you have a much longer notation... 8.5e3 is shorter than 8.500e3

Is it not better to get a Discord server for this... because I feel it would make it easier to keep track of comments, latest Infos, and probably use tools like "live streaming" to tackle some Questions, or do we have this already? :)

"...in C++, we use the letter ‘e’ (or sometimes ‘E’) to represent the “times 10 to the power of” (AS) part of the equation."

Shouldn't "AS" add in the sentence above?

I wanted first to thank you for this fabulous, amazing, fantastic section that I even wasn't able to figure it out during high school. But now it makes sense to me. Outstanding explanations!

"numbers in scientific notation are written with one digit before the decimal, and the rest of the digits afterward."

Shouldn't it be written as " numbers in scientific notation are written with one digit before the decimal POINT, and the rest of the digits afterward."

Because decimal point is that full stop or dot (.) and decimal is the whole fraction( a number which is less than one). What do you think?

Agreed, lesson updated, thanks!

Question g) 34500.0, the solution:

"Even though the decimal point doesn’t affect the value of the number, it affects the precision..."

Should that read

"Even though the zero after the decimal point doesn’t affect the value of the number, it affects the precision..."

or have I misunderstood part of the lesson?

This tutorial is great and I really enjoy learning C++ with it.

However, in this lesson there is a logic mistake (which has been already mentioned by Yann, but has not been answered by the authors):

You state properly that 87.00 is much more precise than 87 and therefore, the trailing zeros after the floating point must be kept to indicate that it is something in the range [86.995, 87.005)*. However, if you convert 146000 to 1.46e5 you lose precision, because 1.46e5 could have originally been any number in [1.455e5, 1.465e5). Obviously, 146000 is much more accurate, only allowing the range [145000.5, 146000.5).

Therefore, for the very same (and correct) argument that 87.00 must be converted in scientific notation into 8.700e2, 146000 must be converted into 1.46000e5 instead of 1.46e5.

*[... , ...) is a mathematical notation for a range from the first to the last number, indicating that the first number is included in the range and the latter number is not.

Thanks for the reminder, I updated the quiz to preserve the trailing zeroes :)

But then wont it disobey this rule:

"Trim off any trailing zeros (on the right end of the significant) only if the original number had no decimal point. >>We’re assuming they’re not significant unless otherwise specified.<<"

Like say:

A guy asks another to convert the number 10 to its scientific notation. The other guy thinks, "Hmmm, now that he didn't ask for 10.0, he doesn't care for precision". And then he gives the answer 1e1.

In short, I personally think the answer should be 1.46e5.

Try few online calculators/converters.

you guys, this made it really confusing for us beginners.

which one is the right notation or are BOTH correct notations but just one is more preferred ?

i also converted 146000 to 1.46e5 .. is this going to cause an issue in coding if its not 1.46000e5 ?

for example 146000000000

if this were to be like 1.46000000000e11 then wouldn't this defeat the purpose ?

now its longer than the original value.

why cant this be 1.46e11

also why in f) 0.0000000008 the precision is not preferred ?

its 8e-10 instead of 8.0e-10 if we were to follow precision.

"now its longer than the original value."

that's exactly what confused me. Like how is 1.46000001e5 any easier to read?

How is it able to put a decimal in 42030 after 4? because to the right of a decimal is less then 1

"The number 5e-2 is equivalent to 5 * 10-2, which is 5 / 102, or 0.05"

Can you explain it?

What is 5 multiplied 10-2 which is 5 divided 102 or 0.05

What is all this?

Because math? :)

10^-2 is the equivalent of 1 / 10^2. The rest is just simple multiplication and division.

"By convention, numbers in scientific notation are written with one digit before the decimal, and the rest of the digits afterward"

Why?

I don't know the answer to this question.

You had only given the answer, it's by convention or by standard. Otherwise there will be multiple representations for same floating point number.

For example -

Number 1234.56 can be represented as 12.3456, 123.456, 12345.6, etc.

When representing some number in computer it must be unambiguous and vice-versa each representation should represent a unique value.

> In order to maximize the quantity of representable numbers, floating-point numbers are typically stored in normalized form. This basically puts the radix point after the first non-zero digit. In normalized form, 50 is represented as 5.000 × 101.

From http://steve.hollasch.net/cgindex/coding/ieeefloat.html

Explain this "though there might be scientific reasons, if you’re using the source code as documentation".

The C++ compiler doesn't care whether you use 87 or 87.000. But, in standard scientific notation, we prefer to keep the trailing zeros since they're useful in determining actual precision. If someone is reading your program, they might care that it was 87 vs 87.000 (e.g. if they're looking to understand how precise you were being in the first place).

Let's say I have a program that reads values with trailing zeroes from a file, does some math on them, then prints to the console. This chapter suggests the value printed to console will not have trailing zeroes if the math was done with floating point numbers, since C++ doesn't care about those.

If I wanted to correctly maintain significant digits throughout mathematical operations, how would I do so?

You'll have to count the digits after the decimal point and keep track of them. I wrote you a type and iostream functions that preserve the precision. You'll understand how it works after chapter 9.

I wasn't able to test `std::from_chars`, because my standard implementation is lacking behind. If it doesn't work, comment line 21-25 and uncomment 28-34.

Example input/output

Hello

I think there is a logic error with the roundings. The weight of the second apple was 87.000g, so it's at the precision of 5 numbers.

The apple cant be between 86.9950g and 87.0049g, since the first one rounded to the precision of 5 numbers would be 86.995 and the second one 87.005. Therefore the second apple can be between weights of 86.9995g to 87.00049.

If I am mistaken please remove my comment to not confuse others. I hope my english was understandable, not my first nor second language ;)

I believe you are correct. So as not to make the numbers too hard to read, I reduced the precision of "87.000" to "87.00".

In the last example of the quiz, I don't understand why it is 3.45000e4 instead of 3.45e4, in the former lecture you said that it doesn't matter if the number is whole(integer) or has .000 at the end. E.g. 34500 and 34500.0 will be same to compiler and both evaluated to the same value.

True, but the quiz instructions say: "keep trailing zeros after the decimal"

There is error in top of the page saying 10e4 is 10000 when its really 100000

It's not saying that. It's saying 10^4 = 10,000, and so 1.2 x 10^4 = 12,000.

Hello,

For the quiz, at question 1d, I don't fully agree with you when you state "trailing zeros in a whole number with no decimal are not significant.".

IMO, if 146000 has only 3 significant digits, it means it can be a rounding of any value between 145500 and 146499 included... So for me, 146000 has really 6 significant digits.

Thanks for your great tutorial. I rediscover C++ after long years where I didn't practice it and is a good refresh and an opportunity to learn what have been introduced with newer C++ flavors.

I had the exact same reaction, but I think it's just easier to count it as having 3 significant digits. Because if we count the trailing zeros in whole numbers with no decimal as significant digits, then if you only want 3 significant digits you'd have to use a power of ten, and maybe it's just more practical not to.

That being said, it means that if you want to display that number with 6 significant digits, you'd use the scientific notation (146e3), and if you want only 3, you'd write the number without the power of ten (146000), so maybe it's not a big deal (even though it's not very consistent with the rest).

I just noticed there is a lack of comments on this lesson,

probably because there is a bunch of math included.

Just wanted to say hi and thank you for all of this OP.

The lack of comments is not because of math, (and previous lessons and most concepts of c++ is math) it’s because this lesson was created APRIL 23RD, 2019 while other lessons were created 2007.

Thank you for this lesson as I was a bit disappointed that you kept mentioning scientific notation/Avogardo's number without giving any proper explanations, when you were giving your float variable lessons.

I am glad you finally made a lesson on this.

This is being a math lesson (for kids) more than being a C++ lesson

(Although kids wont learn CPP but...Meh :/

I'm 16 and i'm learning it.

I'm 13 and i am learning c++. I started coding at 10.

I´m 39, I couldn´t study when I was younger so I´m thankful for this lesson.

Trolling on such an amazing c++ lesson

0.0078900 How is it able to move the decimal to the right of the 7? this makes the 7 a whole integer, and why not trim trailing zeros?

The whole idea of scientific notation is to standardize how we write large numbers. To make them all in the form of 1.234 x 10^5 we multiple or divide by 10 until we get the number that we want.

In this case 0.0078900 x 10 = 0.078900 x 10 = 0.78900 x 10 = 7.8900

To get the number we wanted we multiplied by 10 3 times or in other words we multiplied by 1000. But the thing is that we want to still represent the same number. 7.8900 and 0.0078900 are different numbers, so to preserve the original number we have to note how many times we should divide by 10 to get back to the original.

7.8900 x 10^-3 is the answer that we get. 7.8900 is the proper format we need for scientific notation, and x 10^-3 tells us that we have to divide by 10 3 times to get back to our original number.

If that last part is confusing, it works that way just because of exponential notation. 10 to the -3 power really just means 1 divided by 10 to the 3rd power, which is just another way to say divide by 1000 or divide by 10 3 times.

I tried to break it down into a more basic understanding for you, hope it helps.

Not trimming the 0s shows us that the number is accurate up to that point. When making measurements in real life 0.00789 can actually be 0.0078909 because the tool you were using to measure wasn't precise enough to see the extra 09 at the end of 0.0078909. Writing 0.0078900 tells everyone that your tool was precise up to the last two 0s. Anything past that can be random numbers. So for example if you write 0.0078900, the real number CANNOT be 0.0078930, 0.0078909, or 0.0078944, but it CAN be 0.007890034. Our tool isn't precise enough to see those last 34, but the 00 after 789 we can be sure of!

Hope this makes things more clear.

Good explanation for the "not trimming zeros" part - couldn't really wrap my head around it, so thanks :)