(C++) String to Double 转换器不准确,并且对于负数完全错误。我究竟做错了什么?

(C++) String to Double converter is inaccurate and totally wrong with negative numbers. What am i doing wrong?

我们的老师给了我们这个练习:

"给定一个像'-5,14'这样的字符串写一个函数returns-5,14

的浮点值

我在这里使用双精度只是为了测试精度,但它也不适用于浮点数。

[另外我来自欧洲,我们使用逗号而不是点。哦,我们也不允许使用字符串和布尔类型,我们必须像在 C]

中那样“制作”它们

这是我想出来的,似乎有点效果。正数相似,但错误,给定一个负数,结果类似于给定数的正数的10倍。

它应该是这样工作的:

但由于某种原因,它无法正常工作。数字越小,越不准确(给定 4,5 结果为 9,但给定 345,543 结果为 350,43)

#include <iostream>

#define EOS '[=10=]'
#define DIM 100

#define TRUE 1
#define FALSE 0

void leggiN(char* c)
{
    std::cout << "Insert a number: ";
    std::cin >> c;
}

double stof(char* str)
{
    double Result = 0;
    double ascii_to_int = 48;

    int i = 0;
    int j = 0;

    int IntegerDigits = 0;
    int DecimalDigits = 0;
    int CommaIndex;

    int isNegative = FALSE;

    if (str[0] == '-')  
    {
        IntegerDigits = -1;
        isNegative = TRUE;
    }

    while (str[i] != ',')   
    {
        ++IntegerDigits;
        ++i;
    }

    CommaIndex = i;  
    ++i;                

    while (str[i] != EOS)   
    {
        ++DecimalDigits;
        ++i;
    }

    for (i = (CommaIndex - 1); i >= 0; --i)
    {
        Result += (str[i] - ascii_to_int) * (std::pow(10, j));
        ++j;
    }

    j = 0;

    for (i = (CommaIndex + 1); str[i] != EOS; ++i)
    {
        Result += (str[i] - ascii_to_int) * (std::pow(10, -j));
        ++j;
    }

    if (isNegative == 1)
        Result = Result * -1;

    return Result;
}

int main()
{
    char str[DIM];

    leggiN(str);

    std::cout << stof(str);
}

使用 j = 1 开始第二个 for 循环。您正在尝试计算 10 的 -0

次方
j = 1;

    for (i = (CommaIndex + 1); str[i] != EOS; ++i)
    {
        Result += (str[i] - ascii_to_int) * (std::pow(10, -j));
        ++j;
    }

如果你的代码return9.0时输入"4,5",你的问题与不精确无关。

您的代码中还有其他问题,我已尝试解除它并遇到 SEGFAULT...

#include <iostream>

#define EOS '[=10=]'  // 0 being such a special value, there is no need to 
                  // define a named constant for it.
#define DIM 100  

#define TRUE 1    // the language defines boolean values, avoid defining
#define FALSE 0   // unnecessary named constants for something that already
                  // exists.  

void leggiN(char* c)
{
    std::cout << "Insert a number: ";
    std::cin >> c;     // Inserting from cin to a char* is a BIG no-no.
                       // some compilers won't even allow it, for good reasons
                       // i.e.: what is the length of the array pointed to?
}

double stof(char* str)  // you are indicating that you may modify str? 
{
    double Result = 0;
    double ascii_to_int = 48;   // this is a terrible name.

    int i = 0;
    int j = 0;

    int IntegerDigits = 0;
    int DecimalDigits = 0;
    int CommaIndex;

    int isNegative = FALSE;

    if (str[0] == '-')  // is str a valid pointer? what happens if NULL ??
    {
        IntegerDigits = -1;
        isNegative = TRUE;

        // you fail to skip the sing character, should have ++i here.
    }

    while (str[i] != ',')   // what happens if there is no ',' in the string?
    {                       // you should check for str[i] == 0.  
        ++IntegerDigits;
        ++i;
    }

    CommaIndex = i;  
    ++i;                

    while (str[i] != EOS)   
    {
        ++DecimalDigits;   // why do you count decimal digits?
        ++i;               // you do not use this result anyway... 
    }


    for (i = (CommaIndex - 1); i >= 0; --i)
    {
        // what happens if you have non-digit characters?  they participate
       // in the conversion??
        // you call std::pow(), but do not include <cmath> at the top of the file.
        // isn't str[i] - '0' clearer ? 
        Result += (str[i] - ascii_to_int) * (std::pow(10, j));
        ++j;
    }

    j = 0;

    for (i = (CommaIndex + 1); str[i] != EOS; ++i)
    {
        Result += (str[i] - ascii_to_int) * (std::pow(10, -j));
        ++j;
    }

    if (isNegative == 1)  // you had defined constants fot this, but don't use them.
        Result = Result * -1;  

    return Result;
}

int main()
{
    char str[DIM];

    leggiN(str);

    std::cout << stof(str);
}

这是一种实现您想要的方法。

#include <iostream>
#include <string>

const char DECIMAL_POINT = ',';  // we'll use a named constant here....
                                 // usually, we'd have to check the locale
                                 // for regional specific information.

// works like atod(), conversion stops at end of string of first illegal character.
double stof(const char* str) {

  // check input, must be not null, not empty 
  if (!str || str[0] == 0)
    return 0;

  int i = 0;
  bool isNegative = false;

  // take care of leading sign 
  if (str[0] == '-' || str[0] == '+') {
    isNegative = (str[0] == '-');
    ++i;
  }

  // convert integer part.  

  double result = 0;
  while ('0' <= str[i] && str[i] <= '9') {
    result = (result * 10) + (str[i] - '0');
    ++i;
  }

  // only do decimals if they are there.
  if (str[i] != DECIMAL_POINT) 
    return (isNegative) ? -result : result;

  ++i;  // skip decimal point

  double decimals = 0;
  double multiplier = .1;

  while ('0' <= str[i] && str[i] <= '9') {
    decimals += (str[i] - '0') * multiplier;
    ++i;
    multiplier *= .1;
  }

  result += decimals;

  return (isNegative) ? -result : result;
}

int main() {

  // always use std::string to read strings from cin.
  std::string str;
  std::cout << "Insert a number: ";
  std::cin >> str;

  std::cout << "in: " << str << " out: " << stof(str.c_str()) << '\n';

  return 0;
}