2

Continuing the question, which was closed: C++: "auto" keyword affects math calculations?

As people suggested I modified the code by adding "f" suffix to floating-point values.

#include <cmath>
unsigned int nump=12u;
auto inner=2.5f;
auto outer=6.0f;
auto single=2.f*3.14159265359f/nump;
auto avg=0.5f*inner+0.5f*outer;
for (auto i=0u;i<nump;++i){
    auto theta=i*single;
    auto px=avg*sin(theta);
    auto py=avg*cos(theta);
    auto tw=17.f;
    int v1=std::round(1.f+px-tw/2.0f);
    int v2=std::round(2.f+py-tw/2.0f);
    std::cout<<"#"<<i<<":"<<v1<<";"<<v2<<std::endl;
}

versus

#include <cmath>
unsigned int nump=12u;
float inner=2.5f;
float outer=6.0f;
float single=2.f*3.14159265359f/nump;
float avg=0.5f*inner+0.5f*outer;
for (unsigned int i=0u;i<nump;++i){
    float theta=i*single;
    float px=avg*sin(theta);
    float py=avg*cos(theta);
    float tw=17.f;
    int v1=std::round(1.f+px-tw/2.0f);
    int v2=std::round(2.f+py-tw/2.0f);
    std::cout<<"#"<<i<<":"<<v1<<";"<<v2<<std::endl;
}

The result is exactly the same - output differs between two versions. So does it mean that "auto" always evaluates floating point value to "double" type?

BorisV
  • 683
  • 3
  • 20
  • 5
    … no it doesn’t. In the code you’ve posted it evaluates to `float`. More generally, it evaluates to the type *of the initialiser expression*, whatever that is. The type of `2.5` is `double`, the type of `2.5f` is `float`. That’s all there is to it. – Konrad Rudolph Feb 09 '22 at 10:58
  • Highly related, if not a duplicate: https://stackoverflow.com/questions/71048332/does-auto-keyword-always-evaluates-floating-point-value-as-double – πάντα ῥεῖ Feb 09 '22 at 10:59
  • 4
    @πάνταῥεῖ You’ve linked to this question. – Konrad Rudolph Feb 09 '22 at 11:00
  • But no matter what suffix I use the result outputs differ in exactly same manner. – BorisV Feb 09 '22 at 11:00
  • 1
    It all boils down using `float` literals explicitly and correctly. – πάντα ῥεῖ Feb 09 '22 at 11:01
  • *"output differs between two versions."*. I got same output [here](http://coliru.stacked-crooked.com/a/15f69d8395dff777)... – Jarod42 Feb 09 '22 at 11:05
  • *Does `auto` keyword always evaluates `float` value as `double`?* **No**, `auto` **never** evaluates `float` values as `double`; `auto` only evaluates `double` values as `double`. – Eljay Feb 09 '22 at 15:48

2 Answers2

8

The issue is that your code is using ::sin instead of std::sin (and the same for cos). That is, you’re using the sin function found in the global namespace.

std::sin is overloaded for float. But ::sin isn’t, and it always returns a double (because ::sin is the legacy C function, and C doesn’t have function overloading).

Use std::sin and std::cos in your code to fix the issue.

Konrad Rudolph
  • 530,221
  • 131
  • 937
  • 1,214
  • That's interesting. Without specifying `using namespace std;` and including only `cmath`, ADL is still choosing `std::sin` when resolving `sin` on my clang implementation. I'm genuinely curious how that is happening, as based on what you're saying, it prevents me from replicating the OPs problem (and I suspect I'm not the only one). – WhozCraig Feb 09 '22 at 11:16
  • @WhozCraig, No ADL here since there's no `std` type involved. It could be defining `std::sin` and then `using std::sin;` in the global namespace since you'd be doing `#include ` to get the C one specifically. – chris Feb 09 '22 at 11:20
  • @WhozCraig Like Chris said, this isn’t due to ADL but rather due to the fact that libc++ doesn’t correctly namespace the C++ functions. I *think* this is a bug in the implementation (IIRC because libc++ implements the legacy C headers in terms of the C++ ones, rather than the other way round). – Konrad Rudolph Feb 09 '22 at 11:23
  • That would make sense. Sorry about the ADL ref. super tired and waiting on a build before crashing. Does the same thing for `round`, btw, if I strip the `std::` spec. Still pulls in the `std` function. So that drilled-in habit of always prefacing standard lib functions with `std::` in C++ no matter what finally pays off. Thx. – WhozCraig Feb 09 '22 at 11:26
2

When you use the literal 2.5f you are already suggesting that the value is a float.

You'll see that if you try using 2.5 as literal when assigning value to an auto variable, it deduces this as double.

auto var1 = 2.5   // deduced as type double
auto var2 = 2.5f  // deduced as type float as suggested in literal
Konrad Rudolph
  • 530,221
  • 131
  • 937
  • 1,214