高精度用法、算法(非常详细)

 高精度 ,就是如果这个数已经无法用int、long long等数据类型表达,那么就要用高精度了。

 高精度一般分为4个步骤:

1、输入

我们在输入的时候,一般用字符串把数字输入,即string或char类型输入。例 

string a;
cin>>a;//字符串输入
char a[100];
cin>>a;//字符数组输入

2、转化为数组,并且倒序存进数组

把这个字符串的每一位转化成数组的每一个空间。并且要倒序存入数组,因为我们输入时是从最高位开始数的,而运算的时候是从最低位个位开始算的,所以倒序存放,例如

string a;
for(int i=0;i<=s.size();i++){
	int b[i]=a[i]-'0';//把字符串的每一位转化成为b数组的每一个空间
}

3、最重要的部分:运算

我们以加法为例:

我们先来模拟一下:

第一步,先看个位,把个位的两个数加起来,如果有进位,那么就如前一位加上1,表示进位,如果没有进位,那么再看下一位。

第二步,重复第一步,直到算到最后一位为止。

程序思路:

用一个数组 z 表示答案。第一行,我们先把两个数字相加,然后再加上原本数组 z 的这一位 z[i] 的值,这里如果前一位 z[i-1] 有进位,那么原本数组 z 的这一位 z[i] 的值就会有数字;第二行,判断这一位数是否有进位,就是如果上一位数 z[i] 比十大,那么就除以10,得到的数就是要进位到下一位数 z[i+1] 的那个数,那么原本上一位 z[i] 的数就要mod 10了。

那么加法运算合起来的代码就是:

z[i]=x[i]+y[i]+z[i];//z数组是答案,x,y数组是要加的数 
z[i+1]=z[i]/10;//进位 
z[i]%=10;//前一位就mod 10 

4、最后一步:输出

因为我们上面是倒序算的,那么现在我们就要正着输出了。第一步,现判断一下,如果结果(这时结果还是倒序的)的最后一位不为0,那么先输出一下;第二步,就从最后的第二位开始,到第一位结束,输出结果即可。

顺便带大家认识一下单精度和双精度以及比较冷门的半精度:

两者区别如下:

一、指代不同

1、单精度:是指计算机表达实数近似值的一种方式。

2、双精度:此数据类型与单精度数据类型(float)相似,但精确度比float高。

二、占用空间不同

1、单精度:范围在负数的时候是从 -3.402823E38 到 -1.401298E-45,而在正数的时候是从 1.401298E-45 到 3.402823E38 。

2、双精度:双精度型占8 个字节(64位)内存空间,其数值范围为-1.79769313486232E308 到1.79769313486232E308。

三、特点不同

1、单精度:数值比以上值小的时候,将会由于尾数的有效位数减少而逐步丧失精度(IEEE 754的规定),或者有的系统则直接采用0值来简化处理过程。

2、双精度:编译时所占的内存空间依不同的编译器而有所不同,是double float数据类型,C/C++中表示实型变量的一种变量类型。

//半精度:

 半精度的格式与单精度的格式类似,最左边的一位仍是符号位,指数有5位宽且以余-16(excess-16)的形式存储,尾数有10位宽,但具有隐含1。

 

如图所示,sign为符号位,0表示这个浮点数为正,1表示这个浮点数为负

先介绍尾数,再说指数,fraction为尾数,有10位长,但是有隐含1,尾数可以理解为是一个浮点数小数点后的数,如1.11,尾数就为1100000000(1),最后的隐含1主要用于计算时,隐含1可能存在可以进位的情况。

exponent为指数位,有5位长,具体表示的值有以下几种情况:

当指数位全为0 ,尾数位也全为0的时,表示的就是0
当指数位全为0,尾数位不全为0时,表示为subnormal value,非规格化浮点数,是一个非常小的数
当指数位全为1,尾数位全为0时,表示的是无穷大,此时如果符号位为0,表示正无穷,符号位为1,表示负无穷
当指数位全为1,尾数位不全为0时,表示的不是一个数
其余情况下,指数位的值减去15就是其表示的指数,如11110表示的就是30-15=15

所以我们可以得到,半精度浮点数的值得计算方式为(-1)^sign×2^(指数位的值)×(1+0.尾数位) 

备注:这里0.尾数位,表示如尾数位为0001110001,则0.尾数位为0.0001110001

2.举例

半精度可以表示的最大值

0 11110 1111111111 计算方法为:

(-1)^0×2^(30-15)×1.1111111111 = 1.1111111111(b)×2^15 = 1.9990234375(d)×2^15 = 65504
半精度可以表示的最小值(除了subnormal  value):

0 00001 0000000000 计算方法为:(-1)^(-1)×2(1-15)=2^(-14),约等于十进制的6.104×10^(-5)


再举一个平常的数,这次反过来,如-1.5625×10^(-1) ,即-0.15625 = -0.00101(十进制转二进制)=  -1.01×2^(-3),所以符号位为1,指数为-3+15=12,所以指数位为01100,尾数位为0100000000。所以-1.5625×10^(-1)用半精度浮点数表示就为1 01100 0100000000

C3/C2都使用的排序时间复杂度:

http://file:///C:/Users/eth/OneDrive%20-%20The%20University%20of%20Nottingham%20Ningbo%20China/%E6%A1%8C%E9%9D%A2/Advanced%20Knowledge/%E7%A8%B3%E5%AE%9A%E6%8E%92%E5%BA%8F%E5%92%8C%E4%B8%8D%E7%A8%B3%E5%AE%9A%E6%8E%92%E5%BA%8F%E7%9A%84%E6%97%B6%E9%97%B4%E5%A4%8D%E6%9D%82%E5%BA%A6.webp

(1)冒泡排序

冒泡排序就是把小的元素往前调或者把大的元素往后调。比较是相邻的两个元素比较,交换也发生在这两个元素之间。所以,如果两个元素相等,我想你是不会再无聊地把他们俩交换一下的;如果两个相等的元素没有相邻,那么即使通过前面的两两交换把两个相邻起来,这时候也不会交换,所以相同元素的前后顺序并没有改变,所以冒泡排序是一种稳定排序算法。

冒泡排序详细介绍,移步:冒泡排序

(2)选择排序

选择排序是给每个位置选择当前元素最小的,比如给第一个位置选择最小的,在剩余元素里面给第二个元素选择第二小的,依次类推,直到第n - 1个元素,第n个元素不用选择了,因为只剩下它一个最大的元素了。那么,在一趟选择,如果当前元素比一个元素小,而该小的元素又出现在一个和当前元素相等的元素后面,那么交换后稳定性就被破坏了。

比较拗口,举个例子,序列5 8 5 2 9,我们知道第一遍选择第1个元素5会和2交换,那么原序列中2个5的相对前后顺序就被破坏了,所以选择排序不是一个稳定的排序算法。

选择排序详细介绍,移步:选择排序

(3)插入排序

插入排序是在一个已经有序的小序列的基础上,一次插入一个元素。当然,刚开始这个有序的小序列只有1个元素,就是第一个元素。比较是从有序序列的末尾开始,也就是想要插入的元素和已经有序的最大者开始比起,如果比它大则直接插入在其后面,否则一直往前找直到找到它该插入的位置。

如果碰见一个和插入元素相等的,那么插入元素把想插入的元素放在相等元素的后面。所以,相等元素的前后顺序没有改变,从原无序序列出去的顺序就是排好序后的顺序,所以插入排序是稳定的。

插入排序详细介绍,移步:插入排序

(4)快速排序

快速排序有两个方向,左边的i下标一直往右走,当a[i] <= a[center_index],其中center_index是中枢元素的数组下标,一般取为数组第0个元素。而右边的j下标一直往左走,当a[j] > a[center_index]。如果i和j都走不动了,i <= j,交换a[i]和a[j],重复上面的过程,直到i > j。 交换a[j]和a[center_index],完成一趟快速排序。

在中枢元素和a[j]交换的时候,很有可能把前面的元素的稳定性打乱,比如序列为5 3 3 4 3 8 9 10 11,现在中枢元素5和3(第5个元素,下标从1开始计)交换就会把元素3的稳定性打乱,所以快速排序是一个不稳定的排序算法,不稳定发生在中枢元素和a[j] 交换的时刻。

快速排序详细介绍,移步:快速排序

(5)归并排序

归并排序是把序列递归地分成短序列,递归出口是短序列只有1个元素(认为直接有序)或者2个序列(1次比较和交换),然后把各个有序的段序列合并成一个有序的长序列,不断合并直到原序列全部排好序。可以发现,在1个或2个元素时,1个元素不会交换,2个元素如果大小相等也没有人故意交换,这不会破坏稳定性。

那么,在短的有序序列合并的过程中,稳定是是否受到破坏?没有,合并过程中我们可以保证如果两个当前元素相等时,我们把处在前面的序列的元素保存在结果序列的前面,这样就保证了稳定性。所以,归并排序也是稳定的排序算法。

归并排序详细介绍,移步:归并排序

(6)基数排序

基数排序是按照低位先排序,然后收集;再按照高位排序,然后再收集;依次类推,直到最高位。有时候有些属性是有优先级顺序的,先按低优先级排序,再按高优先级排序,最后的次序就是高优先级高的在前,高优先级相同的低优先级高的在前。基数排序基于分别排序,分别收集,所以其是稳定的排序算法。

基数排序详细介绍,移步:基数排序

(7)希尔排序(shell)

希尔排序是按照不同步长对元素进行插入排序,当刚开始元素很无序的时候,步长最大,所以插入排序的元素个数很少,速度很快;当元素基本有序了,步长很小, 插入排序对于有序的序列效率很高。所以,希尔排序的时间复杂度会比O(n^2)好一些。由于多次插入排序,我们知道一次插入排序是稳定的,不会改变相同元素的相对顺序,但在不同的插入排序过程中,相同的元素可能在各自的插入排序中移动,最后其稳定性就会被打乱,所以shell排序是不稳定的。

希尔排序详细介绍,移步:希尔排序

(8)堆排序

我们知道堆的结构是节点i的孩子为2 * i和2 * i + 1节点,大顶堆要求父节点大于等于其2个子节点,小顶堆要求父节点小于等于其2个子节点。在一个长为n 的序列,堆排序的过程是从第n / 2开始和其子节点共3个值选择最大(大顶堆)或者最小(小顶堆),这3个元素之间的选择当然不会破坏稳定性。但当为n / 2 - 1, n / 2 - 2, ... 1这些个父节点选择元素时,就会破坏稳定性。有可能第n / 2个父节点交换把后面一个元素交换过去了,而第n / 2 - 1个父节点把后面一个相同的元素没 有交换,那么这2个相同的元素之间的稳定性就被破坏了。所以,堆排序不是稳定的排序算法。

堆排序详细介绍,移步:堆排序

综上,得出结论: 选择排序、快速排序、希尔排序、堆排序不是稳定的排序算法,而冒泡排序、插入排序、归并排序和基数排序是稳定的排序算法

不稳定的排序算法有:快、希、选、堆。

  • 2
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值