将字符串转换为Double时的算术错误

时间:2016-04-26 01:27:48

标签: c++ string double

我正在编写一个函数来将用户提供的字符串转换为double。它适用于某些值,但对其他值则无效。例如

string_to_double("123.45") = 123.45
string_to_double(12345) = 12345

string_to_double(123.4567) = 123.457

我相当肯定这是某种舍入错误,但我没有使用近似值,也没有使用非常小或大的值。我的问题是双重的,为什么我得到这些奇怪的结果,如何更改我的代码以获得更准确的结果?我也将此作为个人挑战,因此使用std::stod等方法的建议无济于事。我相信这个问题发生在第二个for循环中,但我觉得包含整个方法是明智的,因为如果我错过了一些东西,那么就不需要阅读更多的代码。

我的代码

template <class T>
double numerical_descriptive_measures<T>::string_to_double(std::string user_input)
{
    double numeric_value = 0;//Stores numeric value of string. Return value.
    int user_input_size = user_input.size();
    int power = 0;
    /*This loop is for the characteristic portion of the input
    once this loop finishes, we know what to multiply the
    characterstic portion by(e.g. 1234 = 1*10^3 + 2*10^2 + 3*10^1 + 4)
    */
    for(int i = 0;i < user_input_size;i++)
    {
        if(user_input[i] == '.')
            break;
        else
            power++;
    }
    /*This loop is for the mantissa. If this portion is zero, 
    the loop doesn't execute because i will be greater than
    user_input_size.*/
    for(int i = 0;i < user_input_size;i++)
    {
        if(user_input[i] != '.')
        {
            numeric_value += ((double)user_input[i] - 48.0)*pow(10,power-i-1);
        }
        else
        {
            double power = -1.0;
            for(int j = i+1;j < user_input_size;j++)
            {
                numeric_value += ((double)user_input[j] - 48.0)*pow(10.0,power);
                power = power-1.0;
            }
            break;
        }
    }
    return numeric_value;
}

2 个答案:

答案 0 :(得分:2)

问题不在于您产生错误的浮点值,问题是您的打印精度不够:

  context 'and the attachment is zipfile' do
    let(:encoded) { true }
    let(:data) { File.read( Rails.root + 'spec/fixtures/test_files/test.zip') }
    let(:expected_status) { 'new' }
    let(:attachments){{
      "file1" => {
        name: "test.zip",
        type: contentType,
        content: payload,
        base64: encoded
      }
    }}
    context 'and the attachment type is zip' do 
      let(:contentType) { 'application/x-zip-compressed' }
    end

    context 'and the attachment type is octet-stream' do 
      let(:contentType) { 'application/octet-stream' }
    end


    it 'saves each zipped file as a separate payload' do
      expect(TransactionPayload.all.size).to eq 2

这将只打印约六位数的精度。您可以使用std::setprecision或其他方法打印更多内容。

答案 1 :(得分:2)

您的代码没有为&#34; 123.4567&#34;生成错误的值但它一般会产生不正确的值。例如,string_to_double(&#34; 0.0012&#34;)生成(在Visual Studio 2015上)

0.0012000000000000001117161918529063768801279366016387939453125

但正确答案是

0.00119999999999999989487575735580549007863737642765045166015625

(您必须将它们打印到17位有效数字以区分它们。)

问题在于你不能使用浮点转换为浮点数 - 它通常没有足够的精度。

(我已经在我的网站上写了很多关于此的内容;例如,请参阅http://www.exploringbinary.com/quick-and-dirty-decimal-to-floating-point-conversion/http://www.exploringbinary.com/decimal-to-floating-point-needs-arbitrary-precision/。)