3

I'm currently working on a program that is meant to take an octal fraction as an input and convert it to a decimal fraction. So far, I have the part of code that will convert the portion before the decimal point to decimal, just not the floating points after the decimal point. I was trying to use modulus, but was unsuccessful because of my variable being a float.

Is there a way to convert the remaining numbers after the decimal point to decimal from octal? I have posted my code below. Any help is appreciated. Thanks!

int main()
{
    float num;
    int rem = 0;;
    int dec = 0;
    int i = 0;

    cout << "Please enter a number with a decimal point: ";
    cin >> num;

    double ohalf = num - (int)num;
    int half = num;

    while (half != 0)
    {
        rem = half % 10;
        half /= 10; //Converts first have to decimal
        dec += rem *= pow(8, i);
        i++;
    }
    cout << dec;

    i = -1;
    while (ohalf != 0)
    {
        rem = ohalf *pow(8, i); //Converts second half to decimal. *This is where I am stuck*
        i--;
    }
    cout << rem;

    _getch();
    return 0;
}
Justin Farr
  • 183
  • 3
  • 5
  • 16
  • I'd think it'd be a lot easier to process the input as a `string`, [split it at the `'.'` char](http://stackoverflow.com/questions/236129/split-a-string-in-c), use `strtol` on the split strings, properly scale the fractional part, then add them into a `double`. – Andrew Henle Oct 10 '16 at 14:25

3 Answers3

2

Going with the idea that one can remove the decimal point just by multiplying with the base often enough:

"123.456" in base 16 
=> BASE16("1234.56")/16 
=> BASE16("12345.6")/(16*16)
=> BASE16("123456")/(16*16*16)

or 

"123.456" in base 8
=> BASE8("1234.56")/8 
=> BASE8("12345.6")/(8*8)
=> BASE8("123456")/(8*8*8)

So all we need to know is the number of places behind the decimal point. Then we can remove it and use std::stoi to convert the remaining string in the wanted base. As a last step we need divide again through base^number_of_places_after_decimal.

Putting everything together you get something like this:

#include <iostream>
#include <string>
#include <cmath>

using std::cout;
using std::cin;
using std::string;

int main()
{
    int base = 8;
    string value;

    cout << "Please enter a number with a decimal point: ";
    cin >> value;

    size_t ppos = value.find('.');
    if (ppos != string::npos) {
        value.replace(ppos,1,"");
    } else {
        ppos = value.size();
    }

    size_t mpos = 0;
    double dValue = (double)std::stoi(value, &mpos, base);
    if (mpos >= ppos)
    {
        dValue /= std::pow(base, (mpos - ppos));
    }

    std::cout << dValue << '\n';

    return 0;
}
Simon Kraemer
  • 5,700
  • 1
  • 19
  • 49
  • I think you'd be better off passing `&maxp` as the second argument to `std::stoi` so that trailing any trailing characters in the string aren't counted in the power. – Toby Speight Oct 10 '16 at 15:19
  • 1
    P.S. Isn't that an 'octal point' rather than a 'decimal point'? :-p – Toby Speight Oct 10 '16 at 15:20
  • @TobySpeight Adjusted my answer accordingly, thank you for pointing this out. I left the `decimal point` in the text to stay conformant with the question :-P – Simon Kraemer Oct 10 '16 at 15:30
0

If you're confident that both the integer and fractional parts of your floating-point value won't overflow the range of long long int, you could parse both parts separately with std::stoll(), then divide the fractional part by the appropriate power of 8:

#include <cmath>
#include <stdexcept>
#include <string>

double parse_octal_fraction(const std::string s)
{
    std::size_t dotpos;
    auto whole = std::stoll(s, &dotpos, 8);
    if (dotpos+1 >= s.length())
        // no fractional part
        return whole;

    std::size_t fract_digits;
    auto frac = std::stoll(s.substr(dotpos+1), &fract_digits, 8);

    if (s.find_first_not_of("01234567", dotpos+1) != std::string::npos)
        throw std::invalid_argument("parse_octal_fraction");

    return whole + frac / std::pow(8, fract_digits);
}

#include <iostream>
int main()
{
    for (auto input: { "10", "0", "1.", "0.4", "0.04", "1.04", "1.04 ", "1. 04"})
        try {
            std::cout << input << " (octal) == " << parse_octal_fraction(input) << " (decimal)" << std::endl;
        } catch (const std::invalid_argument e) {
            std::cerr << "invalid input: " << e.what() << " " << input << std::endl;
        }
}

The test inputs shown give this output:

10 (octal) == 8 (decimal)
0 (octal) == 0 (decimal)
1. (octal) == 1 (decimal)
0.4 (octal) == 0.5 (decimal)
0.04 (octal) == 0.0625 (decimal)
1.04 (octal) == 1.0625 (decimal)
invalid input: parse_octal_fraction 1.04
invalid input: parse_octal_fraction 1. 04

Toby Speight
  • 27,591
  • 48
  • 66
  • 103
0

in your code

 while (ohalf != 0)
{
    rem = ohalf *pow(8, i); //Converts second half to decimal. *This is where I am stuck*
    i--;
}

ohalf will never be equal to zero so It may have lead to infinite loop

Madhusudan chowdary
  • 543
  • 1
  • 12
  • 20