2016-10-10 5 views
3

В настоящее время я работаю над программой, предназначенной для ввода восьмеричной фракции в качестве входных данных и преобразования ее в десятичную дробь. До сих пор у меня есть часть кода, которая преобразует часть до десятичной точки в десятичную, а не плавающие точки после десятичной точки. Я пытался использовать модуль, но был неудачным из-за того, что моя переменная была плавающей.C++ Преобразование восьмеричной доли в десятичную дроби?

Есть ли способ преобразовать оставшиеся числа после десятичной точки в десятичную с восьмеричного? Я разместил свой код ниже. Любая помощь приветствуется. Благодаря!

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; 
} 
+0

Я думаю, было бы намного легче обрабатывать ввод как 'string', [разделить его на '' .'' char] (http://stackoverflow.com/questions/236129/split-a-string-in-c), используйте 'strtol' в разделенных строках, правильно масштабируйте дробную часть, затем добавьте их в "двойной". –

ответ

1

Идущий с идеей, что можно удалить десятичную точку только путем умножения с базой достаточно часто:

"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) 

Так что все мы должны знать, количество мест после запятой. Затем мы можем удалить его и использовать std::stoi, чтобы преобразовать оставшуюся строку в нужную базу. В качестве последнего шага нам нужно снова разделить base^number_of_places_after_decimal.

Сложив все вместе, вы получите что-то вроде этого:

#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; 
} 
+0

Я думаю, вам будет лучше передать '& maxp' в качестве второго аргумента в' std :: stoi', так что завершение любых завершающих символов в строке не учитывается в мощности. –

+1

P.S. Разве это не «восьмеричная точка», а не «десятичная точка»? :-p –

+0

@TobySpeight Скорректированный мой ответ соответственно, спасибо за указание на это. Я оставил «десятичную точку» в тексте, чтобы он соответствовал вопросу: -P –

0

Если вы уверены, что как целые и дробные части вашего плавающей точки значения не переполнятся диапазон long long int, можно разобрать обе части по отдельности с std::stoll(), а затем разделить дробную часть с помощью соответствующей мощности 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("", 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; 
     } 
} 

тестовые входы, показанные дать этот выход:

10 (восьмеричный) == 8 (десятичный)
0 (восьмеричный) == 0 (десятичный)
1. (восьмеричный) == 1 (десятичный)
0,4 (восьмеричный) == 0,5 (десятичный)
0,04 (восьмеричное) == 0,0625 (десятичное)
1,04 (восьмеричное) == 1,0625 (десятичное)
неверный ввод: parse_octal_fraction 1,04
неверный ввод: parse_octal_fraction 1. 04

0

в коде

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

ohalf никогда не будет равна нулю, так это может быть привести к бесконечному циклу