-2

I've written a program in C and Im using cJSON to encapsulate data and send up to Firebase.

I simply want the number to be a number so I can do some calculations on it in Firebase.

This is where it gets messy.

double 24.9

This gives back

24.899999999999999

So eg,

round((399 / 16.0) * 10.0) / 10.0 = 24.8999999

I only want one decimal place, I want 24.9, I need it to be represented as a number. Looks like I might just have to do a sprintf() and use a RAW in cJSON. Unless there's another way in C to keep my 24.9 as 24.9.

This question is not enquring about how floating point works. I am aware of issues. I have not however seen a suitable method to solve it.

Simon
  • 1,385
  • 1
  • 11
  • 20
  • 4
    Possible duplicate of [Is floating point math broken?](https://stackoverflow.com/questions/588004/is-floating-point-math-broken) – Blaze Oct 26 '18 at 14:55
  • 3
    Why do you think there is a problem here? `cJSON` is sending “24.899999999999999” to Firebase. That is enough digits that Firebase can reconstruct the exact value in your `double`. If it is using the same floating-point format, which is likely, that is likely what will do. So the value in Firebase will have the same value as in your C `double`. What is wrong with that? You write “I simply want the number to be a number so I can do some calculations on it in Firebase.” But “24.899999999999999” will be as much of a number in Firebase as “24.9” is. So you have obtained the goal you say you want. – Eric Postpischil Oct 26 '18 at 15:09
  • Now, maybe you have 24.9, and the actual number in the C `double`, which is 24.89999999999999857891452847979962825775146484375, is not what you want. In that case, you have a problem working in C, before you even get to cJSON. To keep 24.9, you might have to keep it as a string in C. However, even if you do, what happens when you get to Firebase? Does it use decimal for arithmetic, or does it use the common 64-bit binary floating point (IEEE-754 basic 64-bit binary floating point)? If it is using binary, you simply cannot have 24.9 in it. – Eric Postpischil Oct 26 '18 at 15:13
  • @EricPostpischil [Firebase does not seem to use decimal](https://firebase.google.com/docs/firestore/manage-data/data-types) – Antti Haapala -- Слава Україні Oct 26 '18 at 15:47
  • I don't believe this to be a duplicate. I am aware if the issues with floating point representation. What I haven't yet seen is a solution too how to display them properly. I've seen recommendations to use round, ceil, floor etc... But a float is all float. – Simon Oct 27 '18 at 11:27

2 Answers2

1

C floating point can't do that.

What you can do is represent the number in milli-whatever like this:

int 24900

You'd be surprised how often it is the most viable solution when systems wish to express and communicate floating point

Andreas
  • 5,086
  • 3
  • 16
  • 36
  • I think I'm liking this approach. Unfortunately I didn't see much of a viable solution anywhere else. Sounds like I'm on the right track though. Either I modify cJSON to output a string without wires to do I can format the number with sprintf or use a number without decimal be changing the measurement. So eg c centimetre becomes millimetre. I think I'm favoring the mili approach. – Simon Oct 27 '18 at 11:23
0

dec24.9 is to binary what dec1/3 is to decimal : a number with an infinite number of decimals.

The only way (I'm aware of - there might be actual solutions) to pass through this difficulty is to put the number into a string, using sprintf indeed.

char *num = malloc(); //Large enough to contain the result or else... SEGFAULT
sprintf(&num, "%.2f", YOUR_MATH_HERE);
Jean-Marc Zimmer
  • 537
  • 6
  • 20
  • I always used it like this and never had a problem. (also I have to admit I like `asprintf();` which also initiates the string.) – Jean-Marc Zimmer Oct 28 '18 at 17:33
  • 1
    What you have shown might work with `asprintf()` but it does not with [`sprintf()`](http://www.cplusplus.com/reference/cstdio/sprintf/). –  Oct 28 '18 at 17:35