iT邦幫忙

0

C++ 次方數型別的錯誤紀錄 pow()

  • 分享至 

  • xImage

#我是c++的菜鳥,我想來發文記錄一下我的學習#

今天我在寫zerogudge 的題目,a040(阿姆斯壯數)的時候發生了很詭異的事情,
當我執行的時候可怕的是就發生了!!

我輸入:99 1000 //註解:搜尋99到1000的阿姆斯壯數。

程式輸出:370 371 407//註解:99到1000的阿姆斯壯數。

What!! 什麼鬼,153到哪裡去了??
本因該輸出:153 370 371 407的阿~

以下是我發現錯誤前的程式碼

#include <iostream>
#include <math.h>
using namespace std;

int get_length(int x)
{
	int leng=0;
	while(x)
	{
		x/=10;
		leng++;
	}
	return leng;
}

int get_sum(int y)
{
    int n=get_length(y);
    int sum=0;
    for(int i=n;i>0;i--)
   {
    int single=y/pow(10,i-1);
    single =single % 10;
    double singlePow=pow(single,n);
    sum=singlePow+sum;
    
}
    return sum;
    
}

int main()
{
    int start;
    int end;
    int count=0;
    cin>>start;
    cin>>end;
    for(;start<=end;start++)
    {
        if(get_sum(start)==start)
        {
            cout<<start<<" ";
            count=count+1;
        }
    }
    if(count==0)
    {
        cout<<"none"<<endl;
    }
    
}

不過後來我把有存pow()這個函式的型別從int改成double就解決這個問題了,
但是為什麼會這樣我還是不太清楚。

各位高手如有閒情雅致就請幫我解答吧~~

神威 iT邦研究生 4 級 ‧ 2020-07-10 14:55:41 檢舉
程式碼不要PO圖片,請用編輯列的這圖示: </> 把你的程式貼上去,不然把你的程式重打一次很麻煩,沒人要幫你
淺水員 iT邦大師 6 級 ‧ 2020-07-10 16:39:06 檢舉
請用編輯功能,把程式碼貼出來。貼程式碼的方式可參考:
https://i.imgur.com/o15rs31.png
這題只有「海綿寶寶」能解。
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

2 個回答

1
淺水員
iT邦大師 6 級 ‧ 2020-07-11 01:21:49
  1. 使用浮點數時要注意會有精度的問題(有可能會有誤差)
  2. 浮點數轉整數會無條件捨去,因此假設是 0.99999... 會變成 0

一般這類型題目不會使用浮點數去計算,而是用整數處理。也許可以自己寫一個整數版的 pow 函式。

額外補充,下列這兩段程式碼一個是 #include<math.h> 另一個是 #include<cmath>
但是在我的電腦一個會輸出 124,另一個會輸出 125
(如果是寫 C++ 要引用 C語言的函式庫,都是引用 cxxxx,而不是 xxxxx.h,細節可以再查一下網路)

#include <iostream>
#include <math.h>

int main()
{
    int x=pow(5,3);
    std::cout<<x; //我的電腦會輸出124
    return 0;
}
#include <iostream>
#include <cmath>

int main()
{
    int x=pow(5,3);
    std::cout<<x; //我的電腦會輸出125
    return 0;
}

PS. 這邊我只是順便提一下引用函式庫的問題,但用整數來處理才是正常的做法。

大神你好,如果型別用double的話,標頭檔用<math.h>和就沒差了

我這樣說對嗎?

淺水員 iT邦大師 6 級 ‧ 2020-07-12 01:40:32 檢舉

標頭檔的問題我也沒深入研究,只是在C++我習慣用 cxxxx 而不是 xxxxx.h

用 double 是不是就沒問題,我的答案是「否」。
浮點數,不管是 float 或是 double 都有精度的問題。
轉換成整數數值時都可能發生 124.99999 變成 124 的問題。

以這個題目來說,因為知道結果是整數,而且誤差是極小的。所以在轉換成整數前,我會加上 0.5,這樣被無條件捨去的話就差不多是四捨五入。(其實加上0.01就很夠了,都可)

建議關於浮點數產生的問題,可以多研究一下。

總結一下:

  1. 數學函數計算出的數值,回傳浮點數時,往往會有誤差,只是這個誤差一般作科學計算是可以直接使用的。
  2. 大於零的浮點數轉換成整數的過程中,會使用無條件捨去小數點的方式。
  3. 以這題來說,比較好的做法是用整數處理次方的問題,而不是直接用內建函式來計算。
  4. 如果真的要用內建的數學函式,在已知結果是整數下,可以取最接近的整數,而不是無條件捨去。

PS. 我不是大神

淺水員 iT邦大師 6 級 ‧ 2020-07-12 01:55:50 檢舉

提供參考,整數版本的 pow 函數

//計算 x 的 p 次方(省略負數與超出範圍的檢查)
int pow(int x, int p)
{
    int r=1;
    for(;p;p>>=1) {
        if(p&1){
            r*=x;
        }
        x*=x;
    }
    return r;
}
0
海綿寶寶
iT邦大神 1 級 ‧ 2020-07-11 13:03:26

我測了一下
不管是double singlePow=pow(single,n);
或是int singlePow=pow(single,n);
答案都是「153 370 371 407」

跟 int/double 沒有關係

為什麼會沒有 150?
可能你把「99 1000」輸入成「199 1000」或「299 1000」了
/images/emoticon/emoticon06.gif

我要發表回答

立即登入回答