程序设计II第一次实验题思路(高精浮点数乘法)

2021-03-31

16:30:44

A、浮点数的幂
贡献者程序设计2
提交情况
1 / 8

题目描述

Time limit: 10000 ms
Memory limit: 256 MB
Standard I/O

给定一个 正浮点数F 和一个 正整数n ,其中:

  1. F包括小数点固定有“六位”,它会被写成0.1234或 .12300或 00123. 的形式;小数点一定存在,允许前导零、后导零、前导或后导小数点的存在,数值位不会全零。
  2. n取值范围为1到10(含边界)。
    求F的n次方的精确值。

输入描述

输入有若干行(不给出具体数目),每行依次包含:

  1. F,占6列;
  2. 一个空格;
  3. n,占两列,右对齐,数值不足两列(1到9)用空格补充。

输出描述

输出包括若干行,每行包括一个F的n次方的精确值,但:

  1. 前导零和后导零应被清除,如012.340应以12.34输出;但0.0123应以.0123输出。
  2. 后导小数点应被清除,如12. 应以12输出;但前导小数点,如 .12,必须保留。

【数据说明】
你将被测试所有的输入组合,祝你好运。
这里我们强烈建议你使用C的输入输出函数,特别是逐字符输入输出,而非C++的流输入输出。 你将被分配每个数据点10s的运行时间。
函数:

#include<stdio.h>
int getchar(void);
int putchar(int);

可以逐字符从stdin读取/向stdout输出字符,一般来讲,它比我们常用的scanf要快。但本题的时限应该足以让你使用scanf通过。

在未知数据组数时如何依次读取:

char str[10];
int n;
while (scanf("%s%d", str, &n) == 2){
    solve();
}

或者:

char ch;
while ((ch = getchar()) != EOF){
    ......
}

请在 https://zh.cppreference.com/w/c 查阅关于scanf或getchar返回值的信息,以及宏定义EOF。对于后一种使用getchar()的代码,小心每行的回车符。

样例输入

6.7592  9
98.999 10
00001.  4
.00001  4

样例输出

29448126.764121021618164430206909037173276672

90429072743629540498.107596019456651774561044010001
1
.00000000000000000001
整体思路:首先将输入浮点数字符串转化为整形数组,再进行高精运算,最后考虑小数点的添加。
  1. if (F[0] == '0')
            {
                for (i = 0; (i < F.size()) && F[i] == '0'; )
                {
                    i++;
                }
            }
    
  2. for (int j = 0; j < F.size() - i; j++)
            {
                if (F[i] == '.'&&j==0)
                {
    
                    j++;
                    k = F.size() -i - 1;
                }
                if (F[i + j] == '.')
                {
                    k = F.size() - i - j - 1;
                    j++;
                    if (i + j == F.size())
                        break;
                }
                F1.push_back(F[i + j]);
            }
    
  3. string operator *(string str1, string str2)
    {
        reverse(str1.begin(), str1.end());
        reverse(str2.begin(), str2.end());
        string str;
        int x = str1.size(), y = str2.size();
        long long k = 0, pre = 0;
        for (int i = 1; i <= str1.size() + str2.size() - 1 || k != 0; i++) {
            for (int j = 1; j <= i; j++) {
                if (j - 1 < 0 || j - 1 > x - 1 || i - j<0 || i - j>y - 1) continue;
                pre += (str1[j - 1] - '0') * (str2[i - j] - '0');
            }
            str.push_back((pre + k) % 10 + '0');
            k = (pre + k) / 10;
            pre = 0;
        }
        reverse(str.begin(), str.end());
        return str;
    }
    
  4.  

    F2 = F1;
            for (int q = 1; q < n; q++)
            {
                F2 = F1 * F2;
            }
    
  5.  

    int l4 = F2.size();
            reverse(F2.begin(), F2.end());
            for (t = 0; F2[t] == '0' && t < n * k; t++)
            { 
            }
            reverse(F2.begin(), F2.end());
    
  6.  

    for (int i = 0; i < l4-t; i++)
            {
                if ((i == l4 - k*n)&&(l4-k*n>0))
                {
                    cout << ".";
                    
                }
                else if (l4 - k * n <= 0&&i==0)
                {
                    cout <<".";
                    for (int m = 0; m < k*n-l4; m++)
                    {
                        cout << 0;
                    }
                }
                cout << F2[i];
            }
    

 上面的6步方法卡掉了,在这里补上。

1.删除前导0。

2.把原输入字符串以整数转存到新的字符串当中并找到和记录小数点的位置。

3.重载乘号*,使其支持string*string高精类

4.指数幂的运算

5.多余后导0的删除

6.小数点的插入和结果的输出

 

下面介绍以上六部的必要性:

test1:0002

test2: 1.00

test3: 002.120

test4: .0020

以上4组数据可供测试

除了重载*外,下面再介绍一个双string类型的高精算法,同重载*一样,注意string类的输入顺序,从右到左,需使用reverse函数

 

/*高精乘模板,注意倒序
void gaojingchengfa(string a,string b)
{
    int l1 = a.length(), l2 = b.length();
    for (int i = 0; i < l1; i++)
    {
        na[i] = a[i]-48;
    }
    for (int i = 0; i < l2; i++)
    {
        nb[i] = b[i] - 48;
    }
    int jw;//上一轮计算进位
    for (int i = 0; i < l1; i++) {
        jw = 0;
        for (int j = 0; j < l2; j++) {
            //交叉乘积
            c[i + j] = na[i] * nb[j] + jw + c[i + j];//当前乘积+上次乘积进位+原数
            jw = c[i + j] / 10;//处理进位
            c[i + j] %= 10;
        }
        c[i + l2] = jw;//进位设置
    }
    //删除前导零
    lenc = l1 + l2;
    for (int i = lenc - 1; i >= 0; i--) {
        //因为我们是从索引 0 开始,所以最高位是保存在 len-1
        if (0 == c[i] && lenc > 1) {
            //注意要有 lenc>1 这个条件。考虑特殊情况,加法结果为 00,我们实际要输出 0。
            lenc--;
        }
        else {
            //第一个不是零的最高位,结束删除
            break;
        }
    }
}
*/

 

  下面为本题完整代码,如有优化,可与me进行交流沟通

#include<iostream>
#include<string>
#include <sstream>
using namespace std;
int na[1000000], nb[1000000], c[20000000],lenc;
//重载乘号
string operator *(string str1, string str2)
{
    reverse(str1.begin(), str1.end());
    reverse(str2.begin(), str2.end());
    string str;
    int x = str1.size(), y = str2.size();
    long long k = 0, pre = 0;
    for (int i = 1; i <= str1.size() + str2.size() - 1 || k != 0; i++) {
        for (int j = 1; j <= i; j++) {
            if (j - 1 < 0 || j - 1 > x - 1 || i - j<0 || i - j>y - 1) continue;
            pre += (str1[j - 1] - '0') * (str2[i - j] - '0');
        }
        str.push_back((pre + k) % 10 + '0');
        k = (pre + k) / 10;
        pre = 0;
    }
    reverse(str.begin(), str.end());
    return str;
}//三

int main()
{
    string F, F1,F2;
    int n, i;
    int k,t;
    while (cin >> F >> n)
    {
        k = 0;
        i = 0;
        if (F[0] == '0')
        {
            for (i = 0; (i < F.size()) && F[i] == '0'; )
            {
                i++;
            }
        }//一
        for (int j = 0; j < F.size() - i; j++)
        {
            if (F[i] == '.'&&j==0)
            {

                j++;
                k = F.size() -i - 1;
            }
            if (F[i + j] == '.')
            {
                k = F.size() - i - j - 1;
                j++;
                if (i + j == F.size())
                    break;
            }
            F1.push_back(F[i + j]);
        }//二
        F2 = F1;
        for (int q = 1; q < n; q++)
        {
            F2 = F1 * F2;
        }//四
        int l4 = F2.size();
        reverse(F2.begin(), F2.end());
        for (t = 0; F2[t] == '0' && t < n * k; t++)
        { 
        }
        reverse(F2.begin(), F2.end());//五
        for (int i = 0; i < l4-t; i++)
        {
            if ((i == l4 - k*n)&&(l4-k*n>0))
            {
                cout << ".";
                
            }
            else if (l4 - k * n <= 0&&i==0)
            {
                cout <<".";
                for (int m = 0; m < k*n-l4; m++)
                {
                    cout << 0;
                }
            }
            cout << F2[i];
        }//六
        cout << endl;
        F.clear();//记得清空
        F1.clear();
    }
}

  

 

 

 

posted @ 2021-03-31 16:31  黯战丿风魂  阅读(157)  评论(0)    收藏  举报