Difference between narrowing and truncation in C++?

Viewed 610

I've been going through a book (C++ Programming Language Stroustrup 4th ed). An example given in a section related to Initialization as below:

void f(double d, int i)
{
    int a{ d };     // error : possible truncation
    char b{ i };    // error : possible narrowing
}

What exactly is the difference between truncation and narrowing?

4 Answers

A narrowing conversion is basically any conversion that may cause a loss of information. Strictly speaking, a narrowing conversion is :

an implicit conversion

  • from a floating-point type to an integer type, or
  • from long double to double or float, or from double to float, except where the source is a constant expression and the actual value after conversion is within the range of values that can be represented (even if it cannot be represented exactly), or
  • from an integer type or unscoped enumeration type to a floating-point type, except where the source is a constant expression and the actual value after conversion will fit into the target type and will produce the original value when converted back to the original type, or
  • from an integer type or unscoped enumeration type to an integer type that cannot represent all the values of the original type, except where the source is a constant expression whose value after integral promotions will fit into the target type, or
  • from a pointer type or a pointer-to-member type to bool.

Notice that this means both of the conversions you posted are narrowing conversion. int a{ d }; is the first case and char b{ i }; is the fourth.

Truncation only occurs when converting between a floating point type and an integer type. It generally refers to the decimal portion of the floating point number being lost (source). This implies that truncation is a subset of narrowing conversions.

What exactly is the difference between truncation and narrowing?

Truncation shortens a decimal-based value such as a float or a double to its integral form int with the extra precision bits after the decimal (from 2-1 in corresponding decimal form) removed.

A double can be truncated to a float as well, with the possibility of an overflow (depending on size of the value) and removal of half of the precision bits in its binary form (since double has twice the precision of float, with them ordinally being 64 and 32 bit floating points respectively).

For an example of double being truncated into a float, consider something which goes atleast above 23 precision bits (considering the mantissa of float) such as the value of PI, regarding which BenVoigt gave an example in the comments.

The value of PI as given by a double is:

11.001001000011111101101010100010001000010110100011000
// 3.141592653589793116

Note that there are 52 precision bits (according to IEEE 754 standard, from 0 to 51), or the bits forming the value after the decimal.

Corresponding truncated float value:

11.0010010000111111011011
// 3.1415927410125732422

Note the inaccuracy for the value of PI in relative terms of the number considered above. This is caused by the removal of the trailing bits of precision when truncating the value from double to float (which has only 23 precision bits, from 0 to 22), ordinally decreasing the precision bits in this case.

Following the conversion of floating-point values to integral form, you can say it acts similar to a floor function call.

Narrowing is shortening of the value as the name implies as well, but unlike truncation it is not restricted to shortening of a floating-point value to an integer value. It applies to other conversions as well, such as a long to an int, a pointer type to a boolean and a character to an integer (as in your example).

Maybe its best understood with an example...

Lets say d == 3.1415926 then in your code a will end up as 3. That is truncation.

On the other hand, if i == 1000 then that is outside the range of char. If char is unsigned the value will wrap around and you will get 1000%256 as the value of b. This happens because int has a wider range than char, hence this conversion is called narrowing.

double d=2.345;
int a = d; // a is 2 now, so the number 2.345 is truncated

As for int to char, char has size of 1 byte, while int has 4 bytes (assuming 32 bit), so you would be "narrowing" variable i.

It could be just about english :) You can look up the words in a dictionary so it may be clearer.

Related