热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

大数相乘-整型数(二)

不再以10进制为单位目前是10000进制性能有极大的提升$Id:multi.cpp82006-11-0305:54:04ZJiangMiao

 不再以10进制为单位
目前是10000进制

性能有极大的提升

//  $Id: multi.cpp 8 2006-11-03 05:54:04Z JiangMiao $ 
//  JiangMiao's Blog  http://blog.csdn.net/antter
#include  " stdafx.h "
#include 
< iostream >
#include 
< string >
#include 
< list >
using   namespace  std;

#define  SAFE_DELETE(p) if((p)!=NULL){delete p;p=NULL;}
#define  SAFE_DELETE_ARRAY(p) if((p)!=NULL){delete[] p;p=NULL;}
typedef unsigned 
long  DWORD;
#define  OK 0
#define  FAIL (DWORD)-1
#define  BLOCK 4  // 块位数
#define  BLOCKS 10000  // 1e+4 即10000进制
#define  BLOCKNUM(size) size/BLOCK+(size%BLOCK>0) // 由size得到最大块数

class  bignumFunc
    {
    
    
public :
    
///  转换字符串为
    inline  static  DWORD strToInt( const   string &  inold,DWORD *&  rt,size_t &  length,size_t &  point) 
        {
        
string   in ;
        size_t insize
= inold.size();
        
in .reserve(insize);
        
// point=insize;
        point = FAIL;
        
for (size_t i = 0 ;i < insize;i ++ )
            {
            
if (inold[insize - i - 1 ] == ' . '
                {
                point
= i;
                
continue ;
                }
            
in .append( 1 ,inold[insize - i - 1 ]);
            }
        SAFE_DELETE_ARRAY(rt);
        size_t size
= in .size();
        size_t num
= BLOCKNUM(size);
        rt
= new  DWORD[num];
        
for (size_t i = 0 ;i < num;i ++
            {
            DWORD s
= 0 ;
            size_t pos
= 0 ;
            
for (size_t j = 0 ;j < BLOCK;j ++ )
                {
                pos
= i * BLOCK + BLOCK - 1 - j;
                
if (pos >= in .size())
                    {
                    
continue ;
                    }
                s
= s * 10 + in [pos] - ' 0 ' ;

                }
            rt[i]
= s;
            
if (pos >= in .size())
                
break ;
            }
        
if (point == FAIL)
            {
            length
= BLOCKNUM(size);
            point
= size;
            }
        
else
            {
            length
= BLOCKNUM(size - 1 );
            }
        
return  OK;
        }

    };
class  bignum
    {

    DWORD
*  str;
    size_t length;
    size_t point;

    
public :
    bignum():str(NULL),length(
0 ),point( 0 )
        {
        }
    
~ bignum()
        {
        }
    bignum(
const  bignum &  b)
        {
        init(b.length);
        length
= b.length;
        point
= b.point;
        memcpy(str,b.str,length);
        }
    size_t size()
        {
        
return  length;
        }
    DWORD reset()
        {        
        SAFE_DELETE_ARRAY(str);
        length 
=   0 ;
        point 
=   0 ;
        
return  OK;
        }

    
//  分配空间
    DWORD init(size_t length)
        {
        reset();
        str
= new  DWORD[length];
        memset(str,
0 ,length * sizeof (DWORD));
        
return  OK;
        }

    
//  读入string
    DWORD read( const   string &   in )
        {
        
return  bignumFunc::strToInt( in ,str,length,point);
        }
    DWORD read(
const  DWORD *   in ,size_t length)
        {
        
return  OK;
        }

    
// 输出到string
     string  toString()
        {
        
string  rt;
        rt.reserve(length
* sizeof (DWORD));
        size_t i;
        
for (i = 0 ;i < length;i ++ // 进位
            {
            DWORD num
= str[i];
            DWORD o
= num % BLOCKS;
            DWORD c
= num / BLOCKS;
            str[i
+ 1 ] += c;
            str[i]
= o;
            }
        
for (i = length - 1 ;i >= 0 ;i -- // 去头零
            {
            
if (str[i] != 0 )
                
break ;

            }

        
for (;i != FAIL;i --
            {
            
char  buf[ 16 ];
            _ultoa_s(str[i],buf,
16 , 10 );
            
for (size_t k = 0 ;k < 4 - strlen(buf);k ++
                {
                
if (rt.size() == 0 // 补足4位
                     break ;
                rt
+= ' 0 ' ;
                }
            rt
+= buf;
            }
        
return  rt;
        }

    
    
/* *
     * 大数相乘,任意位数
     
*/
    
static  bignum *  mul(bignum *  rt,bignum *  sa,bignum *  sb)
        {
        size_t la
= sa -> length;
        size_t lb
= sb -> length;
        size_t xs
= sa -> point + sb -> point; // 小数位数
        size_t lr = la + lb;  // 最大可能位数
        DWORD *  a = sa -> str;
        DWORD
*  b = sb -> str;
        rt
-> init(lr);
        DWORD
*  r = rt -> str;
        size_t ia,ib,ir;
        size_t k
= 1 ;
        
for (ia = 0 ;ia < la;ia ++ // 相乘
            {
            
for (ib = 0 ;ib < lb;ib ++ )
                {
                k
++ ;
                ir
= ib + ia;
                r[ir]
+= a[ia] * b[ib];
                
if (r[ir] >= BLOCKS)  // 进位
                    {
                    
                    DWORD num
= r[ir];
                    DWORD o
= num % BLOCKS;
                    DWORD c
= num / BLOCKS;
                    r[ir
+ 1 ] += c;
                    r[ir]
= o;
                    }
                }
            }
        
if (r[lr - 1 ] == 0 )
            lr
-- ;

        rt
-> length = lr;
        rt
-> point = xs;
        
return  rt;
        }
    };

class  bignumBuilder
    {
    
public :
        
static  bignum *  build( const   string &  str)
            {
            bignum
*  bn = new  bignum();
            bn
-> read(str);
            
return  bn;
            }
    };

/*

Revision: 6
2006-11-2 5:30
提升性能的改进设想:
1. 使用char* 代替string
2. 多数相乘返回非string,最后由intToStr进行字串输出,可极大地节省预处理和生成的时间

实现以上两点性能提升至少45%,乱猜的 :)
-------------------------------------------

Revision: 6.1
2006-11-3
修改
1. 不再以单个字符为单位
2. 位数不在受到限制

提升性能的改进设想:
使用16进制.对取余和进位采取位操作


性能提升 1300%
-------------------------------------------
*/


///  以下为测试文件
#include  " windows.h "
int  main( int  argc, char **  argv)
    {
    
string  rt;
    bignum
*  an = new  bignum();
    bignum
*  bn = new  bignum();
    bignum
*  cn = new  bignum();
    LARGE_INTEGER fre,begin,end;
    QueryPerformanceFrequency(
& fre);
    QueryPerformanceCounter(
& begin);

//     100000阶乘测试
    cn -> read( " 1 " );
    
for ( int  i = 1 ;i <= 10000 ;i ++ )
        {
        bignum
*  tmp = an;
        an
= cn;
        cn
= tmp;
        
char  b[ 6 ];
        _itoa_s(i,b,
10 );
        bn
-> read(b);
        bignum::mul(cn,an,bn);
        }

    QueryPerformanceCounter(
& end);
    cout
<< " Spend  " << (end.QuadPart - begin.QuadPart) * 1000000 / fre.QuadPart << " ns " << endl;
    cout
<< cn -> toString().size() << endl;
    
return   0 ;
    }


/*  测试10000!的结果
 * C4 2.66MHZ

revision: 6
Spend 16911238ns //17s
35660.

------------------------
revision: 7
10000阶乘
Spend 8441291ns (8.5秒)提升100%
35660

//1000位大浮点数相乘
Spend 3147ns
2001
------------------------
revision: 8
Spend 593560ns (0.6秒)提升1300%
35660
请按任意键继续. . .
 
*/

 

欢迎探讨,

我的Blog是http://blog.csdn.net/antter

Email: jmiwork@yahoo.com

QQ: 185500511


推荐阅读
  • 本文主要解析了Open judge C16H问题中涉及到的Magical Balls的快速幂和逆元算法,并给出了问题的解析和解决方法。详细介绍了问题的背景和规则,并给出了相应的算法解析和实现步骤。通过本文的解析,读者可以更好地理解和解决Open judge C16H问题中的Magical Balls部分。 ... [详细]
  • 本文讨论了使用差分约束系统求解House Man跳跃问题的思路与方法。给定一组不同高度,要求从最低点跳跃到最高点,每次跳跃的距离不超过D,并且不能改变给定的顺序。通过建立差分约束系统,将问题转化为图的建立和查询距离的问题。文章详细介绍了建立约束条件的方法,并使用SPFA算法判环并输出结果。同时还讨论了建边方向和跳跃顺序的关系。 ... [详细]
  • 本文介绍了一种划分和计数油田地块的方法。根据给定的条件,通过遍历和DFS算法,将符合条件的地块标记为不符合条件的地块,并进行计数。同时,还介绍了如何判断点是否在给定范围内的方法。 ... [详细]
  • 本文介绍了UVALive6575题目Odd and Even Zeroes的解法,使用了数位dp和找规律的方法。阶乘的定义和性质被介绍,并给出了一些例子。其中,部分阶乘的尾零个数为奇数,部分为偶数。 ... [详细]
  • CF:3D City Model(小思维)问题解析和代码实现
    本文通过解析CF:3D City Model问题,介绍了问题的背景和要求,并给出了相应的代码实现。该问题涉及到在一个矩形的网格上建造城市的情景,每个网格单元可以作为建筑的基础,建筑由多个立方体叠加而成。文章详细讲解了问题的解决思路,并给出了相应的代码实现供读者参考。 ... [详细]
  • Linux环境变量函数getenv、putenv、setenv和unsetenv详解
    本文详细解释了Linux中的环境变量函数getenv、putenv、setenv和unsetenv的用法和功能。通过使用这些函数,可以获取、设置和删除环境变量的值。同时给出了相应的函数原型、参数说明和返回值。通过示例代码演示了如何使用getenv函数获取环境变量的值,并打印出来。 ... [详细]
  • 本文为Codeforces 1294A题目的解析,主要讨论了Collecting Coins整除+不整除问题。文章详细介绍了题目的背景和要求,并给出了解题思路和代码实现。同时提供了在线测评地址和相关参考链接。 ... [详细]
  • 本文详细介绍了GetModuleFileName函数的用法,该函数可以用于获取当前模块所在的路径,方便进行文件操作和读取配置信息。文章通过示例代码和详细的解释,帮助读者理解和使用该函数。同时,还提供了相关的API函数声明和说明。 ... [详细]
  • Nginx使用(server参数配置)
    本文介绍了Nginx的使用,重点讲解了server参数配置,包括端口号、主机名、根目录等内容。同时,还介绍了Nginx的反向代理功能。 ... [详细]
  • 本文介绍了C++中省略号类型和参数个数不确定函数参数的使用方法,并提供了一个范例。通过宏定义的方式,可以方便地处理不定参数的情况。文章中给出了具体的代码实现,并对代码进行了解释和说明。这对于需要处理不定参数的情况的程序员来说,是一个很有用的参考资料。 ... [详细]
  • c语言\n不换行,c语言printf不换行
    本文目录一览:1、C语言不换行输入2、c语言的 ... [详细]
  • 本文介绍了P1651题目的描述和要求,以及计算能搭建的塔的最大高度的方法。通过动态规划和状压技术,将问题转化为求解差值的问题,并定义了相应的状态。最终得出了计算最大高度的解法。 ... [详细]
  • 本文介绍了解决二叉树层序创建问题的方法。通过使用队列结构体和二叉树结构体,实现了入队和出队操作,并提供了判断队列是否为空的函数。详细介绍了解决该问题的步骤和流程。 ... [详细]
  • 本文介绍了C函数ispunct()的用法及示例代码。ispunct()函数用于检查传递的字符是否是标点符号,如果是标点符号则返回非零值,否则返回零。示例代码演示了如何使用ispunct()函数来判断字符是否为标点符号。 ... [详细]
  • 《数据结构》学习笔记3——串匹配算法性能评估
    本文主要讨论串匹配算法的性能评估,包括模式匹配、字符种类数量、算法复杂度等内容。通过借助C++中的头文件和库,可以实现对串的匹配操作。其中蛮力算法的复杂度为O(m*n),通过随机取出长度为m的子串作为模式P,在文本T中进行匹配,统计平均复杂度。对于成功和失败的匹配分别进行测试,分析其平均复杂度。详情请参考相关学习资源。 ... [详细]
author-avatar
骚扰list_238
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有