-2

Edit(Third time): Responding to the answers so far, let me clear something:

  • @Lưu Vĩnh Phúc as he acutely pointed out, in my original expression,

the precision of an arithmetic operation is decided by the precision of the less precise operand.

I should use accuracy instead of precision. I.e.

the accuracy of an arithmetic operation is decided by the accuracy of the less accurate operand.

YES, I accidentally used precision instead of accuracy, and continued to use it in many of my argument. I apologize for my stupid mistake and corresponding confusion.

So the question is restated:

For example:

auto test=100. *3.f;

Then, the variable test is of double type.

I am puzzled by this choice. Because mathematically speaking, the accuracy of an arithmetic operation is decided by the accuracy of the less accurate operand. In our case, 3.f has already been unable to guarantee its accuracy after at most 8 digits, what's the point of storing test as a double with a possibly misleading impression of 15-digit precision?

My guess is it is possibly related to the exponent, but in this case, the result is 300 which doesn't fall out of the range of float. Or is there any historical reason?

Many thanks,


I apologize again for my stupidity.


To summarize the answers so far: 1, yes, it's about range; 2, when double*float->double, there is a lot of truncation.

Flowing Cloud
  • 433
  • 1
  • 4
  • 8
  • 1
    Thats not a VS thing, not even a C++ thing, every programming language does it like this. – tkausl Jul 02 '16 at 06:57
  • Quotes from the standard in three, two, one... – Martin G Jul 02 '16 at 06:59
  • 1
    ...[zero](http://eel.is/c++draft/expr): "_...Otherwise, if either operand is double, the other shall be converted to double..._" – mkal Jul 02 '16 at 07:08
  • 1
    Your edit doesn't make any more sense than your original question. The result of `1.1 * 1.5` is 1.65, for the reasons given in my answer. `1.5 * 1.2 = 1.80`, for the same reason. – user207421 Jul 02 '16 at 07:21
  • Think about it: if your 1 only has one precision, what will be your answer? 1.65 or 1.80? You don't know. So the answer only make sense up to 1. Again, you are confusing the abstracted mathematical exact 1 (or literal 1) with an estimation of it (a float number) in storage. – Flowing Cloud Jul 02 '16 at 07:39
  • 1
    In any base, the product of an n-digit and and m-digit number is an (n+m) digit number, so even `int*int -> int` produces twice the number of bits it can have. Storing the result in a type narrower than the original ones is even worse. `double*float->double` requires a lot of truncation, there's no point storing the result in float – phuclv Jul 02 '16 at 07:49
  • You are apparently using a scientific rule about measured results as though it was a universal rule of mathematics, which it certainly and obviously isn't, and without having mentioned anything about measured results or constants of the universe in your question. Programming language compilers do not implement scientific measured-result principles. They implement what Don Knuth calls Concrete Mathematics. – user207421 Jul 02 '16 at 07:50
  • @ Lưu Vĩnh Phúc Thanks! The truncation part explains a lot. – Flowing Cloud Jul 02 '16 at 08:03
  • @EJP I am glad we finally arrived at the same page...I thought it was about the implementation (or not), I was curious about the advantage of this (except the larger range). Phuc explains it does truncation anyway, that helps me a lot. Do you have any other possible merits? – Flowing Cloud Jul 02 '16 at 08:09

5 Answers5

3

When performing an operation between two types, C++ will return the value with the largest precision. This prevents overflows and other odd things that can happen with narrowing conversions.

As an example, a float can hold up to ~3.4×1038, whereas a double can hold up to ~1.8×10308. If you multiplied a float of 3.0f by a double of 1e100, you would want to get the result of about 3e100, wouldn't you? On the other hand, if you converted that to a float, you would get inf instead.

You could argue that it should be able to tell, but how can a compiler know at compile time whether the result fits into a float or if a double is needed?

It is also worth remembering that all float values can be converted to a double with no loss of precision, but the opposite is (obviously) not true.

To sum up: this is computer science, not maths.

N. Shead
  • 3,828
  • 1
  • 16
  • 22
  • Yes, that is what I guessed. I thought it was something about the exponent. But I just want to double check if there is anything special in terms of computer science that I missed. Thank you for your help. – Flowing Cloud Jul 02 '16 at 07:26
  • Usual disclaimers about unicorn systems apply, but +1. – T.C. Jul 02 '16 at 07:35
0

mathematically speaking, the precision of an arithmetic operation is decided by the precision of the less precise operand.

No it isn't. Mathematically speaking, the precision of multiplication is defined as the product of the precision of the operands. Consider for example 1 * 1.5. Result is 1.5, not 1.

user207421
  • 305,947
  • 44
  • 307
  • 483
  • I think it is your misunderstanding. When you say the result is 1.5, you implicitly assuming your 1 has more precision than 1 digit. Think about it, if your 1 has 1 precision, it might be 1.1, 1.2 and so on. What is your answer? So you are implicitly assume higher precision than you thought. – Flowing Cloud Jul 02 '16 at 07:08
  • @FlowingCloud Don't be silly. If I'm wrong, the answer is one, and it isn't. The misunderstanding is yours. There is another rule for division, and again for addition and subtraction. If you want to maintain counterfactually that the correct answer is one, not 1.5, you need to state why. This is fourth grade arithmetic. And when I write 1 I mean 1, not 1.1, 1.2, ... – user207421 Jul 02 '16 at 07:11
  • Again, it is your misunderstanding. When you use this 1*1.5, you are using its mathematical meaning: that is 1 is exactly 1 which has infinite precision. – Flowing Cloud Jul 02 '16 at 07:20
  • 1
    @FlowingCloud The literal `1` is exactly `1`. – juanchopanza Jul 02 '16 at 07:23
  • @Flowing Cloud Your argument is self-contradictory. 1 is 1. It doesn't need infinite precision for any purpose. If I was using it as having infinite precision, by my own logic I would have had to assert that the correct answer was 1.5000000000000000000000000000000... to an infinite number of decimal places. I've implemented COBOL compiler arithmetic and these are the rules you use. – user207421 Jul 02 '16 at 07:25
  • I think @FlowingCloud is talking about https://en.wikipedia.org/wiki/Significant_figures#Arithmetic. – T.C. Jul 02 '16 at 07:27
  • @T.C. Not unless and until he introduces the term 'measured quantity' into the discussion. – user207421 Jul 02 '16 at 07:30
  • @juanchopanza I understand the literal 1 is exactly 1, therefore 1*1.5=1.5 is fine. but again, this 1 has infinite imprecision which a float doesn't have. That is what I said EJP was implicitly assuming more precision than he thought. – Flowing Cloud Jul 02 '16 at 07:31
  • @EJP Let me ask you a question: do you understand in your equation 1*1.5=1.5 both 1 and 1.5 are mathematical abstractions instead of two digits? Float and double themselves must introduce the error already. – Flowing Cloud Jul 02 '16 at 07:34
  • @FlowingCloud They are not abstractions, they are well-known numbers with precise finite values, *and*, as it happens, precise floating-point representations as well. – user207421 Jul 02 '16 at 07:53
  • @T.C. Thank you for helping clearing things up. – Flowing Cloud Jul 02 '16 at 08:10
  • @EJP yes, they are abstractions. But let's put them away. Could you rewind a little bit to where you almost understood me? I think that's closest point between you and me. – Flowing Cloud Jul 02 '16 at 08:15
0

This is due to the implicit typecasting built in in most programming languages, not just C++. For more detail, you may check out this link:
http://www.cplusplus.com/doc/tutorial/typecasting/

Vaibhav Bajaj
  • 1,934
  • 16
  • 29
  • Saying "all programming languages" is too strong. For example, I know several assembly languages that do no implicit typecasting at all. I suggest changing "all" to "most". – Patricia Shanahan Jul 02 '16 at 10:42
0

According to The C++ Programming Language (4th Edition),

§10.3.1: The result types of arithmetic operators are determined by a set of rules known as "the usual arithmetic conversions" (§10.5.3). The overall aim is to produce a result of the "largest" operand type.

I believe that this was done so as to not lose any data stored in a larger type.

§10.5.3: These conversions are performed on the operands of a binary operator to bring them to a common type, which is then used as the type of the result:

  1. If either operand is of type long double, the other is converted to long double.
    • Otherwise, if either operand is double, the other is converted to double.
    • Otherwise, if either operand is float, the other is converted to float.
    • Otherwise, integral promotions (§10.5.1) are performed on both operands.
  2. Otherwise, if either operand is unsigned long long, the other is converted to unsigned long long.
    • Otherwise, if one operand is a long long int and the other is an unsigned long int, then if a long long int can represent all the values of an unsigned long int, the unsigned long int is converted to a long long int; otherwise, both operands are converted to unsigned long long int. Otherwise, if either operand is unsigned long long, the other is converted to unsigned long long.
    • Otherwise, if one operand is a long int and the other is an unsigned int, then if a long int can represent all the values of an unsigned int, the unsigned int is converted to a long int; otherwise, both operands are converted to unsigned long int.
    • Otherwise, if either operand is long, the other is converted to long.
    • Otherwise, if either operand is unsigned, the other is converted to unsigned.
    • Otherwise, both operands are int.

These rules make the result of converting an unsigned integer to a signed one of possibly larger size implementation-defined. That is yet another reason to avoid mixing unsigned and signed integers.

akhilmd
  • 182
  • 1
  • 8
0

You might have misunderstanding of accuracy and precision

Floating-point types in C++ don't have varied precision. They have fixed number of bits and you can't store 1 with 1-digit precision. It's always 53 bits of precision (assuming IEEE-754 double). Same to 1.5 or 1.766569471, regardless of how many digits you wrote in the text

Floating-point types in computers don't store the precision in the type, so 1.5 is exactly the same as 1.5000000 or 1.500000000000...

Community
  • 1
  • 1
phuclv
  • 37,963
  • 15
  • 156
  • 475