6

Trying to get whole and decimal part of a number into two variables. What I tried:

#include <iostream>
int main(){
    float n,m; int k; std::cin >> n;
    k = n;
    m = n - k;

Tried to convert the float number to int and received warning by the compiler that the number could be incorrect, tested, was incorrect indeed and couldn't get the expected results. Searched on this, couldn't find any other workaround than using floor().

My actual code:

int main() {
    float n; cin >> n;
    int nfloor = n;
    cout << nfloor << "\n";
    float nfloat = n - nfloor; int nfloatfloor;
    cout << nfloat << "\n";
    do {
        nfloat *= 10;
        nfloatfloor = nfloat;
        cout << nfloat << "\n" << nfloatfloor << "\n";
    } while (nfloat > nfloatfloor);
}

Results:

Input: 12.34
Output :
12
0.34
3.4
3
34
34
340
340
3400
3400
34000
34000
340000
340000
3.4e+06
3400001
3.4e+07
34000016

Subtracting two float numbers returns an incorrect value, Searched on this but the answers were on a high level that I couldn't understand.

My actual code:

int main() {
    float n; cin >> n;
    float nfloor = floor(n);
    cout << nfloor << "\n";
    float nfloat = n - nfloor; float nfloatfloor;
    cout << nfloat << "\n";
    do {
        nfloat *= 10;
        nfloatfloor = floor(nfloat);
        cout << nfloat << "\n" << nfloatfloor << "\n";
    } while (nfloat > nfloatfloor);
}

Results:

Input: 12.34
Output:
12
0.34
3.4
3
34
34 //Run should stop here because of the while loop bit it doesn't, funny thing is it gives me different results sometimes, last time it gave me 35 and 34
340
340
3400
3400
34000
34000
340000
340000
3.4e+06
3.4e+06
3.4e+07
3.4e+07

@Slava Take a look at the output right above this sentence, compiler printed 34 and 34, the duplicate answer shows that the couts are 34.0000000000000004 or something like that, and as I commented above, the code should have stopped, what I'm really trying to do is compare a float number and int number, if (float >int) the code should continue and if not it should stop so is there any solution? @hnefatl I tried your answer and the compiler just hangs:

int main() {
    float n2, whole, fractional, fractional2, whole2; cin >> n2;
    int denominator = 1;
    fractional = modf(n2, &whole);
    do {
        fractional *= 10;
        fractional2 = modf(fractional, &whole2);
        denominator *= 10;
    } while (fractional > fractional2);
    if (denominator > 1)
        denominator /= 10;
    cout << denominator;
}
Shayan
  • 709
  • 1
  • 15
  • 31
  • About the comment in the "Results:" part that I said it gives me different results sometimes, I also get different results on Codeblocks compared to VS – Shayan Dec 15 '17 at 18:20
  • Why not use floor? – CodeCollector Dec 15 '17 at 18:22
  • @CodeCollector Please read the full question, on 2nd attempt I used floor() thanks – Shayan Dec 15 '17 at 18:23
  • 1
    If you are going to go from `text`->`float`->`int,int`, you are going to lose a fair bit of precision in the process no matter what you do, you are probably better off tokenizing the string into the component parts directly. –  Dec 15 '17 at 18:25
  • @Frank Actually I'm going from `float` to `int` and not `text` to `float`. – Shayan Dec 15 '17 at 18:29
  • Number you are getting is not incorrect, incorrect is your assumption that you get precise number with floating point variable. – Slava Dec 15 '17 at 18:38
  • @Shayan: if you want to get the proper fractional part your best bet is to go `float` -> text -> `int, int`! The answers who got posted before the question got marked as duplicate don't get you the correct value. – Dietmar Kühl Dec 15 '17 at 18:41
  • @Slava Probs being the question too long, ppl don't bother to read it through ofc, I added some more detail about the issue, this was not a general issue as you duplicated the question, but it's an specific issue. – Shayan Dec 15 '17 at 18:54
  • @Slava How is the duplicate answer is going to solve my issue here? – Shayan Dec 15 '17 at 18:59
  • @Shayan `std::cout` does some rounding so no you do not have 34 and 34 and no it does not have to stop. To compare that values properly use epsilon as already explained in that topic. – Slava Dec 15 '17 at 19:13
  • @Slava Seems like this one is also a dup of my question https://stackoverflow.com/questions/1161199/is-relational-comparison-between-int-and-float-directly-possible-in-c – Shayan Dec 15 '17 at 19:18
  • But the accepted answer suggests to convert float to int which is a horrible idea. – Shayan Dec 15 '17 at 19:19
  • 1
    @Shayan for std::cout see http://en.cppreference.com/w/cpp/io/manip/setprecision – Slava Dec 15 '17 at 19:19
  • @Slava Thanks now I know, I set the precision to 10 and I got `34.00001526` and `34` – Shayan Dec 15 '17 at 19:25
  • 1
    Btw unless you work with hardware acceleration like GPU or something like that better use `double` rather than `float` – Slava Dec 15 '17 at 19:27
  • @Slava Ok, and I just tried the epsilon method. and it worked like a charm so I defined epsilon as 0.0001 and Instead of comparing `nfloat` and `nfloatfloor` I did `while (nfloat - nfloatfloor > epsilon);` – Shayan Dec 15 '17 at 19:29
  • 1
    you better do `fabs(nfloat - nfloatfloor)` – Slava Dec 15 '17 at 19:30

2 Answers2

14

Why not use std::modf, which is designed for this purpose:

float n = 12.34;
float whole, fractional;

fractional = std::modf(n, &whole);

The non-fractional part of the value is in whole while the fractional part is in fractional.


If you then want to get an integer value for the whole part (bearing in mind that you can lose data this way as the range of a float can be larger than that of an int), you can just do:

int integralWhole = static_cast<int>(whole);
hnefatl
  • 5,860
  • 2
  • 27
  • 49
11

Well this should do the trick.

int main(){
    float n; std::cin >> n;

    float whole = floor(n);
    float decimal = n - whole;
    std::cout << whole << "\n";
    std::cout << decimal << "\n";

    std::cin.get();
    return 0;
}
CodeCollector
  • 468
  • 2
  • 13