1

I am using a library for loading Wavefront .obj files into my OpenGL application (tinyobjloader). I noticed that there is an error when loading objects. When I load an object with a coordinate of eg. 0.9999999 it is set to 0. By debugging I found out that the following method produces this behaviour:

static inline float parseFloat(const char*& token)
{
    token += strspn(token, " \t");
    float f = (float)atof(token);
    token += strcspn(token, " \t\r");
    return f;
}

So atof() returns somehow an int, not a float. I read that some compilers don't throw a warning when using atof() without including "stdlib.h" and the result is that atof() returns an integer.

The curious thing is that even if I include "stdlib.h" the error remains. I can't figure out what causes this behaviour.

Any idea?

Tim
  • 135
  • 1
  • 12

2 Answers2

3

The standard says to atof:

Except for the behaviour on error, it is equivalent to strtod(nptr,(char**)NULL)

so yours returning '0' has nothing to do with a float not being able to represent it or similar.

Would you use strtod instead (which you probably should when stringstreams are not an option, just to be able to report errors), then you would likely notice that it stops parsing at the ..

This is a strong indication that you are using a locale that awaits , instead of . as s decimal separator. Depending on how your application works with locales, you might want to run it with a properly set environment variable (e.g. LC_NUMERIC=C) or do a setlocale(LC_NUMERIC,"C"); yourself before any parsing.

In any case you should analyze who in your application is using locale dependent things, and what for, so as to not collide with them. Another possible route is to require locale dependent input everywhere, so everyone needs to give the numbers to you with , as decimal separator.

PlasmaHH
  • 15,673
  • 5
  • 44
  • 57
0

You can see the documentation of atof here . Some Floating points cannot be represented in 32 bits and hence you are getting an error and value returned is zero.

//Try these 
float f = 0.9999999 ;
cout << atof("0.9999999") << " " << f << endl;//output is 1 1 

So what you are seeing is a valid behavior. You may want to try strtod()

kdurga
  • 97
  • 1
  • 8
  • In both cases - atof() and strtod() - I get a zero for the first output. – Tim Jul 19 '13 at 09:46
  • from the standard (about atof): "Except for the behaviour on error, it is equivalent to `strtod(nptr,(char**)NULL)`" so it must parse and round, not return 0. – PlasmaHH Jul 19 '13 at 09:48
  • @TimV: Is it possible that strtod expects , instead of .? – PlasmaHH Jul 19 '13 at 09:48
  • Some things are not exactly representable but that's no excuse for 0.9999999 becoming 0 – doctorlove Jul 19 '13 at 09:54
  • I am getting 1 in both cases and not a zero, can you tell us which compiler/platform you are on? – kdurga Jul 19 '13 at 09:56
  • @ PlasmaHH: In the examples from [here](http://www.cplusplus.com/reference/cstdlib/strtod/) they also use '.' . Even if I just try `cout << strtod("12.34", NULL) << endl;`it returns 12; – Tim Jul 19 '13 at 10:02
  • @kdurga: I'm coding on Fedora 17 using gcc. gcc -version says "gcc (GCC) 4.7.2 20121109 (Red Hat 4.7.2-8)" – Tim Jul 19 '13 at 10:04
  • what does cout << 12.34 << endl give? – doctorlove Jul 19 '13 at 10:05
  • 1
    @TimV: that was not the question. I was asking if your strtod expects , instead of .. just try it. strtod is locale dependent. – PlasmaHH Jul 19 '13 at 10:05
  • @PlasmaHH: That was it. I tried with 0,99999 and it works as expected. How can I influence this behaviour. Is there a way to manually force it to take '.' instead of ','? – Tim Jul 19 '13 at 10:11
  • @TimV: as I said, its locale dependent. Use a locale that has the format you want, possibly C or POSIX instead of a language specific. – PlasmaHH Jul 19 '13 at 10:16
  • Ok, thank you very much. It works now after setting `setlocale (LC_NUMERIC,"C");` – Tim Jul 19 '13 at 10:33