你的位置:首页 > ASP.net教程

[ASP.net教程]使用OC语言编写两个超大数相乘或相加的算法的思路和超大正整数相乘的代码


 

正文:

在编程中,无论是OC还是C亦或是C++语言,所声明的整数变量都会在内存中占有固定的存储空间,而这些存储空间都是固定的。

比如我们知道的int、long、short、unsigend int、unsigend long、unsigend long long等等,都有固定的存储空间,而哪怕是64位系统下的变量unsigend long long,能存储的最大范围只有1844674407370955161。

下边复习一下基础类型的存储范围以及所占字节:

编程语言的基础类型速查表

char -128 ~ +127 (1 Byte)
short -32767 ~ + 32768 (2 Bytes)
unsigned short 0 ~ 65536 (2 Bytes)
int -2147483648 ~ +2147483647 (4 Bytes)
unsigned int 0 ~ 4294967295 (4 Bytes)
long == int
long long -9223372036854775808 ~ +9223372036854775807 (8 Bytes)
double 1.7 * 10^308 (8 Bytes)

unsigned int 0~4294967295  
long long的最大值:9223372036854775807
long long的最小值:-9223372036854775808
unsigned long long的最大值:1844674407370955161

__int64的最大值:9223372036854775807
__int64的最小值:-9223372036854775808
unsigned __int64的最大值:18446744073709551615

 

详细:

====================

符号属性 长度属性 基本型 所占位数 取值范围 输入符举例 输出符举例 
    -- -- char                            8 -2^7 ~ 2^7-1 %c %c 、 %d 、 %u
    signed -- char                    8 -2^7 ~ 2^7-1 %c %c 、 %d 、 %u
    unsigned -- char                8 0 ~ 2^8-1 %c %c 、 %d 、 %u
    [signed] short [int]            16 -2^15 ~ 2^15-1 %hd
    unsigned short [int]           16 0 ~ 2^16-1 %hu 、 %ho 、 %hx
    [signed] -- int                    32 -2^31 ~ 2^31-1 %d
    unsigned -- [int]                 32 0 ~ 2^32-1 %u 、 %o 、 %x
    [signed] long [int]              32 -2^31 ~ 2^31-1 %ld
    unsigned long [int]             32 0 ~ 2^32-1 %lu 、 %lo 、 %lx
    [signed] long long [int]       64 -2^63 ~ 2^63-1 %I64d
    unsigned long long [int]      64 0 ~ 2^64-1 %I64u 、 %I64o 、 %I64x
    -- -- float                            32 +/- 3.40282e+038 %f 、 %e 、 %g
    -- -- double                        64 +/- 1.79769e+308 %lf 、 %le 、 %lg %f 、 %e 、 %g
    -- long double                    96 +/- 1.79769e+308 %Lf 、 %Le 、 %Lg

几点说明: 

1. 注意 ! 表中的每一行,代表一种基本类型。 “[]” 代表可省略。 
    例如: char 、 signed char 、 unsigned char 是三种互不相同的类型; 
    int 、 short 、 long 也是三种互不相同的类型。 

2. char/signed char/unsigned char 型数据长度为 1 字节;
    char 为有符号型,但与 signed char 是不同的类型。 
    注意 ! 并不是所有编译器都这样处理, char 型数据长度不一定为 1 字节, char 也不一定为有符号型。 

3. 将 char/signed char 转换为 int 时,会对最高符号位 1 进行扩展,从而造成运算问题。 
    所以 , 如果要处理的数据中存在字节值大于 127 的情况,使用 unsigned char 较为妥当。 
    程序中若涉及位运算,也应该使用 unsigned 型变量。 

4. char/signed char/unsigned char 输出时,使用格式符 %c (按字符方式);  或使用 %d 、 %u 、 %x/%X 、 %o ,按整数方式输出; 输入时,应使用 %c ,若使用整数方式, Dev-C++ 会给出警告,不建议这样使用。 

5. int 的长度,是 16 位还是 32 位,与编译器字长有关。 
    16 位编译器(如 TC 使用的编译器)下, int 为 16 位; 32 位编译器(如 VC 使用的编译器 cl.exe )下, int 为 32位。 

6. 整型数据可以使用 %d (有符号 10 进制)、 %o (无符号 8 进制)或 %x/%X (无符号 16 进制)方式输入输出。 而格式符 %u ,表示 unsigned ,即无符号 10 进制方式。 

7. 整型前缀 h 表示 short , l 表示 long 。 
    输入输出 short/unsigned short 时,不建议直接使用 int 的格式符 %d/%u 等,要加前缀 h 。这个习惯性错误,来源于 TC 。 TC 下, int 的长度和默认符号属性,都与 short 一致,于是就把这两种类型当成是相同的,都用 int 方式进行输入输出。 

8. 关于 long long 类型的输入输出: 
    "%lld" 和 "%llu" 是 linux 下 gcc/g++ 用于 long long int 类型 (64 bits) 输入输出的格式符。 
    而 "%I64d" 和 "%I64u" 则是 Microsoft VC++ 库里用于输入输出 __int64 类型的格式说明。 

    Dev-C++ 使用的编译器是 Mingw32 , Mingw32 是 x86-win32 gcc 子项目之一,编译器核心还是 linux 下的 gcc 。
    进行函数参数类型检查的是在编译阶段, gcc 编译器对格式字符串进行检查,显然它不认得 "%I64d" , 
    所以将给出警告 “unknown conversion type character `I' in format” 。对于 "%lld" 和 "%llu" , gcc 理所当然地接受了。 
    
    Mingw32 在编译期间使用 gcc 的规则检查语法,在连接和运行时使用的却是 Microsoft 库。 
    这个库里的 printf 和 scanf 函数当然不认识 linux gcc 下 "%lld" 和 "%llu" ,但对 "%I64d" 和 "%I64u" ,它则是 乐意接受,并能正常工作的。 

9. 浮点型数据输入时可使用 %f 、 %e/%E 或 %g/%G , scanf 会根据输入数据形式,自动处理。 
    输出时可使用 %f (普通方式)、 %e/%E (指数方式)或 %g/%G (自动选择)。 

10. 浮点参数压栈的规则: float(4 字节 ) 类型扩展成 double(8 字节 ) 入栈。 
    所以在输入时,需要区分 float(%f) 与 double(%lf) ,而在输出时,用 %f 即可。 
    printf 函数将按照 double 型的规则对压入堆栈的 float( 已扩展成 double) 和 double 型数据进行输出。 
    如果在输出时指定 %lf 格式符, gcc/mingw32 编译器将给出一个警告。 

11. Dev-C++(gcc/mingw32) 可以选择 float 的长度,是否与 double 一致。 

12. 前缀 L 表示 long ( double )。 
    虽然 long double 比 double 长 4 个字节,但是表示的数值范围却是一样的。 
    long double 类型的长度、精度及表示范围与所使用的编译器、操作系统等有关。


我们看到上面所有基础数据类型都是有限的,如果要计算天文数字级的、哪怕是最简单的相加算法,也会造成数据溢出。

比如:

写了个将年龄转为秒的程序,前126年都可以,但是从127开始就overflow了……

在计算机中,当要表示的数据超出计算机所使用的数据的表示范围时,则产生数据的溢出。具体的自己网上可以查看下资料,很好查

 

溢出原因
数据类型超过了计算机字长的界限就会出现数据溢出的情况。导致内存溢出问题的原因有很多,比如:
(1) 使用非类型安全(non-type-safe)的语言如 C/C++ 等。
(2) 以不可靠的方式存取或者复制内存缓冲区。
(3)编译器设置的内存缓冲区太靠近关键数据结构。

因素分析
1.内存溢出问题是 C 语言或者 C++ 语言所固有的缺陷,它们既不检查数组边界,又不检查类型可靠性(type-safety)。众所周知,用 C/C++ 语言开发的程序由于目标代码非常接近机器内核,因而能够直接访问内存和寄存器,这种特性大大提升了 C/C++ 语言代码的性能。只要合理编码,C/C++应用程序在执行效率上必然优于其它高级语言。然而,C/C++ 语言导致内存溢出问题的可能性也要大许多。其他语言也存在内存溢出问题,但它往往不是程序员的失误,而是应用程序的运行时环境出错所致。
2. 当应用程序读取用户(也可能是恶意攻击者)数据,试图复制到应用程序开辟的内存缓冲区中,却无法保证缓冲区的空间足够时(换言之,假设代码申请了 N 字节大小的内存缓冲区,随后又向其中复制超过 N 字节的数据)。内存缓冲区就可能会溢出。想一想,如果你向 12 盎司的玻璃杯中倒入 16 盎司水,那么多出来的 4 盎司水怎么办?当然会满到玻璃杯外面了!
3. 最重要的是,C/C++编译器开辟的内存缓冲区常常邻近重要的数据结构。假设某个函数的堆栈紧接在在内存缓冲区后面时,其中保存的函数返回地址就会与内存缓冲区相邻。此时,恶意攻击者就可以向内存缓冲区复制大量数据,从而使得内存缓冲区溢出并覆盖原先保存于堆栈中的函数返回地址。这样,函数的返回地址就被攻击者换成了他指定的数值;一旦函数调用完毕,就会继续执行“函数返回地址”处的代码。非但如此,C++ 的某些其它数据结构,比如 v-table 、例外事件处理程序、函数指针等,也可能受到类似的攻击。

 

然而,针对这种情况,该怎么防止数据溢出?

一、创建结构体,将溢出的数据转移到另一个变量中存储;

二、创建或设计一个存储器,将所有巨大的数值存储在这个存储器中,算法类似于时钟算法,满多少进一位。再设计一个取出器,将转换后的变量转换成巨大的数值,边转换边计算;

三、创建数组来按位数来存储数据;

 

显然第三种方法简单便捷,比如我们要存储一个123(一百二十三)的数据类型,则创建一个数组int【3】,数组中每个元素对应一位数,怎么设计可以自己去设定,在这里我们使用OC的NSMutableArray数组来计算,在此讲一下C数组和OC数组的区别:

OC 数组是一个对象,有大量的方法,c 没有都需要自己写

C 数组删除是需要后面往前移动,oc 数组自动处理

OC中的数组算是一个封装好的对象,一般的操作基本就能满足了,但是C里面的就仅仅是个连续的内存空间而已。一个是对象一个空间,另外一个C里面的数组是要在定义的时候就要初始化个数,但是OC里面的个数比较动态。

 

这也就是为什么涉及到算法或者比较底层的数据处理一般使用C语言,第一:执行效率高;其次:算法接近初级易于理解和维护,并且大量方法和函数运算规律可以完全自定义。

所以OC涉及到算法极少,一般逻辑居多。OC来做简单的运算也不是不可以,优点在于对于数组的处理比较简便,以下简述一下运算逻辑:

一:多位数相乘,第一个数的个位依次向第二位数的每位依次相乘,个位数与个位数相乘使用int来运算,如果结果是个位数,那么把他放进一个array数组中;

二:如果结果是二位数,则存储个位数,十位数添加到进位变量中,等待下一次相乘时与下一次的结果相加,然后继续进行一步骤;

三:将最后array数组中的元素首尾调换,因为数组元素存储方式是从个位到最高位,与需求数据相反;

四:将这个数组对象存储到另一个数组中,形成OC二维数组;

五:经过以上运算,会获得一个梯形数据:

        1234

      1234

    1234

  1234

需要对二维数组中的前位数组进行补0,为下一步方便运算做准备;

六:补0后数据为:

0001234

0012340

0123400

1234000

之后从上向下依次相加,同样的:

1.第一个数的个位依次向第二位数的每位依次相加,个位数与个位数相乘使用int来运算,如果结果是个位数,那么把他放进一个array数组中;

2.如果结果是二位数,则存储个位数,十位数添加到进位变量中,等待下一次相乘时与下一次的结果相加,并且执行1步骤;

七:最后会获得一个最终结果的数组,同样的,里面数据结构依然与需求数据相反,需要首尾调换;

八:返回这个数组,这个数组的每一个元素(从第一位起到第N位)都是这个最终结果(超大数)从个位到最高位的相应数值:

比如这个超大数是:1231443256827659485683297465789236578263857658265892561856138456938

那么这个数组的元素依次是:1、2、3、1、4、4、3、2、5、6、8、.......5、6、9、3、8

 

OC虽然可以进行处理算法和数据类型,但是相对于C来说,它所占的内存还是比较高的,因为这个数组所开辟的内存空间远远大于相应C数组的空间,它可以存储多个对象,自带各种数据处理方法,灵活多变对于C数组来说操作性很强,毕竟NSArray用于开发。

以下我把OC超大数算法的代码贴出来,仅供参考。。如有不对望指正:

 

 

 

 

#import "Multiplication.h"

 

@implementation Multiplication

 

-(NSString *)MulOfOneString:(NSString *)strOne AndString:(NSString *)strTwo{

    

    NSString *a = [NSString stringWithFormat:@"%lu",(unsigned long)strOne.length];

    NSString *b = [NSString stringWithFormat:@"%lu",(unsigned long)strTwo.length];

    int oneLength = [a intValue];

    int twoLength = [b intValue];

    NSMutableArray *arrOne = [[NSMutableArray alloc]init];

    NSMutableArray *arrTwo = [[NSMutableArray alloc]init];

    for (int i = 0;i < oneLength;i++) {

        unichar c = [strOne characterAtIndex:i];

        NSString *c1 = [NSString stringWithFormat:@"%c",c];

        [arrOne addObject:c1];

    }

    for (int i = 0;i < twoLength;i++) {

        unichar c = [strTwo characterAtIndex:i];

        NSString *c1 = [NSString stringWithFormat:@"%c",c];

        [arrTwo addObject:c1];

    }

    NSMutableArray *arrShi = [[NSMutableArray alloc]init];

    if (oneLength > twoLength) {

        for (int i = twoLength - 1 ;i >= 0;i--) {

            NSMutableString *strJ = [[NSMutableString alloc]init];

            int jin = 0;

            int btwo = [arrTwo[i] intValue];

            for (int j = oneLength - 1; j >= 0;j--) {

                int aone = [arrOne[j] intValue];

                int c = aone * btwo + jin;

                int z = c%10;

                jin = c/10;

                if (j != 0) {

                    [strJ appendFormat:@"%d",z];

                }else{

                    [strJ appendFormat:@"%d",c%10];

                    if (c/10!=0) {

                        [strJ appendFormat:@"%d",c/10];

                    }

                }

            }

            NSMutableString *zheng = [[NSMutableString alloc]init];

            for (NSInteger i = strJ.length-1 ;i>=0;i--) {

                unichar s = [strJ characterAtIndex:i];

                [zheng appendFormat:@"%c",s];

            }

            [arrShi addObject:zheng];

        }

    }else if(oneLength < twoLength){

        for (int i = oneLength - 1 ;i >= 0;i--) {

            NSMutableString *strJ = [[NSMutableString alloc]init];int jin = 0;

            int aone = [arrOne[i] intValue];

            for (int j = twoLength - 1; j >= 0;j--) {

                int btwo = [arrTwo[j] intValue];

                int c = aone * btwo + jin;

                int z = c%10;

                jin = c/10;

                if (j != 0) {

                    [strJ appendFormat:@"%d",z];

                }else{

                    [strJ appendFormat:@"%d",c%10];

                    if (c/10!=0) {

                        [strJ appendFormat:@"%d",c/10];

                    }                     }

            }

            NSMutableString *zheng = [[NSMutableString alloc]init];

            for (NSInteger i = strJ.length-1 ;i>=0;i--) {

                unichar s = [strJ characterAtIndex:i];

                [zheng appendFormat:@"%c",s];

            }

            [arrShi addObject:zheng];

        }

    }else if (oneLength == twoLength){

        for (int i = oneLength - 1 ;i >= 0;i--) {

            NSMutableString *strJ = [[NSMutableString alloc]init];int jin = 0;

            int aone = [arrOne[i] intValue];

            for (int j = twoLength - 1; j >= 0;j--) {

                int btwo = [arrTwo[j] intValue];

                int c = aone * btwo + jin;

                int z = c%10;

                jin = c/10;

                if (j != 0) {

                    [strJ appendFormat:@"%d",z];

                }else{

                    [strJ appendFormat:@"%d",c%10];

                    if (c/10!=0) {

                        [strJ appendFormat:@"%d",c/10];

                    }

                }

            }

            NSMutableString *zheng = [[NSMutableString alloc]init];

            for (NSInteger i = strJ.length-1 ;i>=0;i--) {

                unichar s = [strJ characterAtIndex:i];

                [zheng appendFormat:@"%c",s];

            }

            [arrShi addObject:zheng];

        }

    }

    NSMutableArray *arrBF = [[NSMutableArray alloc]init];

    if (arrShi.count == 1) {

        NSString *res = arrShi[0];

        return res;

    }else{

        for (int i = 0;i<arrShi.count;i++) {

            NSMutableString *str0 = arrShi[i];

            for (int j = 1;j<=i;j++) {

                [str0 appendFormat:@"0"];

            }

            arrBF[i] = str0;

        }

        for (int i =1;i<arrBF.count;i++) {

            int J = 0;

            NSMutableString *strConst = [[NSMutableString alloc]init];

            NSString *strC = arrBF[i-1];

            NSString *strB = arrBF[i];

            if (strC.length == strB.length) {

                for (NSInteger j = strB.length-1 ;j >= 0;j--) {

                    unichar b = [strB characterAtIndex:j];

                    unichar c = [strC characterAtIndex:j];

                    int B = [[NSString stringWithFormat:@"%c",b] intValue];

                    int C = [[NSString stringWithFormat:@"%c",c] intValue];

                    int counst = B + C + J;

                    int z = counst %10;

                    J = counst /10;

                    if (j != 0) {

                        [strConst appendFormat:@"%d",z];

                    }else{

                        [strConst appendFormat:@"%d",counst %10];

                        if (counst /10!=0) {

                            [strConst appendFormat:@"%d",counst /10];

                        }

                    }

                }

                NSMutableString *Lin = [[NSMutableString alloc]init];

                for (NSInteger i = strConst.length-1 ;i>=0;i--) {

                    unichar s = [strConst characterAtIndex:i];

                    [Lin appendFormat:@"%c",s];

                }

                arrBF[i] = Lin;

            }else{

                NSUInteger a = strC.length;

                for (NSInteger j = strB.length-1 ;j >= 0;j--) {

                    unichar b = [strB characterAtIndex:j];

                    unichar c = [strC characterAtIndex:a-1];

                    int B = [[NSString stringWithFormat:@"%c",b] intValue];

                    int C = [[NSString stringWithFormat:@"%c",c] intValue];

                    a--;

                    int counst = B + C + J;

                    int z = counst %10;

                    J = counst /10;

                    if (j != 0) {

                        [strConst appendFormat:@"%d",z];

                    }else{

                        [strConst appendFormat:@"%d",counst %10];

                        if (counst /10!=0) {

                            [strConst appendFormat:@"%d",counst /10];

                        }

                    }

                }

                NSMutableString *Lin = [[NSMutableString alloc]init];

                for (NSInteger i = strConst.length-1 ;i>=0;i--) {

                    unichar s = [strConst characterAtIndex:i];

                    [Lin appendFormat:@"%c",s];

                }

                arrBF[i] = Lin;

            }

        }

        NSString *res = arrBF[arrBF.count-1];

        return res;

    }

    return @"输入有误";

}

 

 

@end

 

 

 

超大数相加算法思路和相乘算法后半段思路相似,相对简单很多

 

以下是超大数相加算法的代码:

 

 

#import "Addition.h"

 

@implementation Addition

 

- (NSString *)additionOfString:(NSString *)strOne AndString:(NSString *)strTwo{

    

    NSMutableString *One = [NSMutableString stringWithFormat:@"%@",strOne ];

    NSMutableString *Two = [NSMutableString stringWithFormat:@"%@",strTwo ];

    

    if (One.length > Two.length) {

        NSInteger t = One.length - Two.length;

        for (NSInteger i = 0;i < t;i++) {

            [Two insertString:[NSString stringWithFormat:@"0"] atIndex:0];

        }

        int jin = 0;

        NSMutableString *strJ = [[NSMutableString alloc]init];

        for (NSInteger i = One.length -1 ; i >= 0 ;i--) {

            unichar onenum = [One characterAtIndex:i];

            unichar twonum = [Two characterAtIndex:i];

            int onum = [[NSString stringWithFormat:@"%c",onenum] intValue];

            int tnum = [[NSString stringWithFormat:@"%c",twonum] intValue];

            int c = onum + tnum +jin;

            int z = c%10;

            jin = c/10;

            if (i !=0 ) {

                [strJ appendFormat:@"%d",z];

            }else{

                [strJ appendFormat:@"%d",c%10];

                if (c/10 != 0) {

                    [strJ appendFormat:@"%d",c/10];

                }

            }

        }

        NSMutableString *zheng = [[NSMutableString alloc]init];

        for (NSInteger i = strJ.length-1; i>=0;i--) {

            unichar k = [strJ characterAtIndex:i];

            [zheng appendFormat:@"%c",k];

        }

        return zheng;

    }else if(One.length < Two.length){

        NSInteger t = Two.length - One.length;

        for (NSInteger i = 0;i < t;i++) {

            [One insertString:[NSString stringWithFormat:@"0"] atIndex:0];

        }

        int jin = 0;

        NSMutableString *strJ = [[NSMutableString alloc]init];

        for (NSInteger i = Two.length - 1; i >= 0 ;i--) {

            unichar onenum = [One characterAtIndex:i];

            unichar twonum = [Two characterAtIndex:i];

            int onum = [[NSString stringWithFormat:@"%c",onenum] intValue];

            int tnum = [[NSString stringWithFormat:@"%c",twonum] intValue];

            int c = onum + tnum +jin;

            int z = c%10;

            jin = c/10;

            if (i !=0 ) {

                [strJ appendFormat:@"%d",z];

            }else{

                [strJ appendFormat:@"%d",c%10];

                if (c/10 != 0) {

                    [strJ appendFormat:@"%d",c/10];

                }

            }

        }

        NSMutableString *zheng = [[NSMutableString alloc]init];

        for (NSInteger i = strJ.length-1; i>=0;i--) {

            unichar k = [strJ characterAtIndex:i];

            [zheng appendFormat:@"%c",k];

        }

        return zheng;

    }else if(One.length == Two.length){

        int jin = 0;

        NSMutableString *strJ = [[NSMutableString alloc]init];

        for (NSInteger i = One.length - 1; i >= 0 ;i--) {

            unichar onenum = [One characterAtIndex:i];

            unichar twonum = [Two characterAtIndex:i];

            int onum = [[NSString stringWithFormat:@"%c",onenum] intValue];

            int tnum = [[NSString stringWithFormat:@"%c",twonum] intValue];

            int c = onum + tnum +jin;

            int z = c%10;

            jin = c/10;

            if (i !=0 ) {

                [strJ appendFormat:@"%d",z];

            }else{

                [strJ appendFormat:@"%d",c%10];

                if (c/10 != 0) {

                    [strJ appendFormat:@"%d",c/10];

                }

            }

        }

        NSMutableString *zheng = [[NSMutableString alloc]init];

        for (NSInteger i = strJ.length-1; i>=0;i--) {

            unichar k = [strJ characterAtIndex:i];

            [zheng appendFormat:@"%c",k];

        }

        return zheng;

    }

  

    return @"您的输入有误!";

}

 

 

 

 

@end