python整除及余数_Java和Python中的整数除法,取余,舍⼊关于除法,你也许觉得没什么值得谈论的,毕竟⼩学的时候体育⽼师就教过我们了。然⽽对于编程中使⽤的除法,我觉得还是有很多值得注意的细节的。为什么我想深究⼀下?因为我⽇常主要使⽤Java和Python编程,⽽它们的除法在细节上有很多不同之处,全是坑啊…所以接下来我也将着重于Java和Python,但是相信我,就算你不⽤Java和Python,也会有所收获的。
1.整数除法
对两个不能整除的整数做除法,就要⾯对舍⼊的问题。和⼤多数编程语⾔⼀样,Java的基本策略是向零取整(round to zero),也就是向绝对值变⼩的⽅向取整。举⼏个⾹甜的⼩栗⼦:3/2=1, -3/2=-1。⽽对于Python⽽⾔,情况就有所不同了。
>>>-1/10
-1```
显然如果按照Java的取整策略,-1/10应该得0,⽽Python给出的结果是-1。事实上Python的取整⽅式是向下取整,也就是向着数轴上负⽆穷的⽅向取整。
好吧,Java和Python的取整⽅式不同,夺⼤点事⼉啊…那么如果我们要在Python下采⽤向零取整的结果,
咋整?⼀种⽐较直接的⽅式是:
```python
>>>int(float(-1)/10)
0```
##2.取余
谁说没⼤事?(╰( ̄▽ ̄)╭) ⼤事来了!
Java和Python整数除法都遵循下⾯这个公式:
>(a/b)*b+c=a
也就是说:
>a mod b=c=a-(a/b)*b
这⾥的/表⽰的是整数除法。既然它们的取整⽅式不⼀样,那么取余也会受到影响:
python转java代码
>For Java: -2 % 3==-2
For Python: -2 % 3==1
在某些实际应⽤中,我们可能会被要求得到⼀个整数的各位数字。如果输⼊的整数的正的,Java和Python都可以⽤相同的⽅法来解决:
```python
def func(a):
pos, res=1, []
while a/pos:
res+=(a/pos)%10,
pos*=10
return res```
Java代码也差不多就是这样了。但如果输⼊的整数是⼀个负数,Java版本的代码还是可以得到正确的结果,⽽Python不能(曾经在这⾥被坑的,举⼿)。那怎样⽤Python正确地搞定这个问题嘞?可以先去绝对值和符号,当正数来处理,最后再在结果⾥搭上符号。
##3. Follow-ups
###3.1 Python中的另⼀个除法操作
我们知道,在Python中,基本的除号“/”是被重载了的。当两个操作数都是整数时,进⾏整数除法,得到整数结果,否则进⾏浮点数除法(真除法),得到浮点数结果。从Python 2.2开始,另⼀个除号被引⼊://,它只执⾏整数除法。注意,//的结果类型依操作数⽽定。
```python
>>>1.0/2
0.0
>>>1.0//2.0
0.0
>>>1//2
>0```
另外,如果想同时得到商和余数,可以使⽤内建的函数divmod,结果是⼀个tuple。
```python
>>>divmod(7, 2)
(3, 1)
>>>divmod(7.0, 2)
(3.0, 1.0)```
###3.2 Python中的舍⼊
除了缺省的舍⼊⽅式,Python还有多种舍⼊可供选择。
**Floor rounding:**
```python
>>>import math
>>>math.floor(1.2)
1.0
>>>math.floor(-1.2)
-2.0```
**Ceiling rounding:**
```python
>>&il(1.2)
2.0
>>&il(-1.2)
-
1.0```
**Round-off:**
```python
>>>round(0.5)
1.0
>>>round(-0.4)
-0.0
>>>round(-0.5)
-1.0```
内嵌的round函数也可以⼀个指定保留⼩数位数的参数:
```python
>>>round(0.21, 1)
0.2
>>>round(0.21, 2)
0.21```
**Caution !**
```python
>>>round(2.675, 2)
2.67
咦?bug啦?!当然不是。这⾥要明确⼀件事:计算机只认识0,1(量⼦计算机?懵)。就是说,我们输⼊的⼗进制数,在计算机内部都是⽤⼆进制来表⽰的。有的⼗进制数可以⽤⼆进制准确地表⽰出来,⽐如⼗进制的0.125可以表⽰为0b0.001;然⽽很多的⼩数是没法⽤⼆进制数精确表⽰的,计算机⾥存储的是它们的近似值,例如⼗进制的0.1,⽤⼆进制表⽰,可以近似为:
0b0.00011001100110011001100110011001100110011001100110011010,所以当我们把它换回⼗进制数以输出或者使⽤,得到的值就是0.1000000000000000055511151231257827021181583404541015625。也就是说,0.1在计算机⾥并不是刚好等于1/10的。
>>>0.1+0.2
0.30000000000000004
同样,当我们运⾏round()函数,也是对计算机中实际存储的值近似取舍。2.67实际上近似为
2.67499999999999982236431605997495353221893310546875,你看第三位⼩数是4,那么round(2.675, 2)就相当于round(2.674, 2),结果当然是2.67。值得注意的是,这种现象是⼴泛存在于各种计算机和各种编程语⾔的,不是bug,只是有的语⾔选择了不让你看到。
3.3 Java中的舍⼊
Java提供了floor和ceil⽅法来实现向下和向上取整。
Math.floor(2.9)
这俩函数简单⽅便,居家旅⾏必备。另外Java中也有个round函数,可以实现各种复杂的取整。
System.out.und(0.5));
//输出 1
System.out.und(-0.5));
//输出 0
System.out.und(-0.51));
//输出 -1```
这什么⿁!Keep Calm and Carry On!
数学上有多种不同的策略来进⾏取整,⽐如我们体育⽼师教的四舍五⼊。各种取整策略的共同点就是要做真值作近似,那就会引⼊偏差。四舍五⼊显然并不是⼀种公平的策略(想想0~4的舍和5~9的得)。
有⼀个叫做银⾏家舍⼊(Banker’s Rounding)的东西,不造你听过没,反正我是最近才知道的。事实上.NET和VB6都是默认采⽤这种⽅式,⽽且IEEE 754默认采⽤这种Rounding。Banker’s Rounding 也就是** round to even **策略。
假设当前考虑那位的数字是d(其实d就是将不被保留的第⼀位),如果d<5,则舍(round to zero);如果d>5,则⼊(round away from zero);⽽当d==5时,就要根据d前后的数位来确定往哪边取了。
>1) 如果d之后存在⾮零的数位,则⼊;
2)如果d之后不存在⾮零的数位,则看d之前的⼀个数位,⽤c表⽰:
a.如果c是奇数,则⼊;
b.如果c是偶数,则舍。
再来⼀把栗⼦,对下列数保留0位⼩数,
第⼀位⼩数就是d,整数位就是c:
>BankRound(0.4)==0,  BankRound(0.6)==1,  BankRound(-0.4)==0,  BankRound(-0.6)==-1
BankRound(1.5)==2.0,  BankRound(-1.5)==-2.0,  BankRound(2.5)==2.0,  BankRound(-2.5)==-2.0
BankRound(1.51)==2.0,  BankRound(-1.51)==-2.0,  BankRound(2.51)==3.0,  BankRound(-2.51)==-3.0
可以看出,Banker’s Rounding对正数和负数的处理是对称的,因此不会引⼊符号带来的偏差。另外它以均等的⼏率来舍⼊数位(考虑c, c有各⼀半的⼏率为奇数和偶数),所以多次舍⼊后与真值的差别会较⼩。
扯了这么多,跟Java的**und( )**有什么关系呢?我也是写到这才发现,好像没什么软(luan)关系。因为它并没有遵循Banker’s rounding。⽽是按照以下策略进⾏取整:
当考虑的数位d不是5,d<5就舍,d>5则⼊。
当d==5:
>a.如果d的右边有⾮零数位,则⼊;
>b.如果d的右边没有⾮零数位,则** round to ceiling**,即对负数舍,对正数⼊。
还有还有, 在Java⾥可以使⽤** BigDecimal **和** RoundingMode **实现更通⽤的取整⽅式。
```java
double d=-2.5;
BigDecimal bd=new BigDecimal(d);
double nd=bd.setScale(0,
RoundingMode.HALF_EVEN).doubleValue();
System.out.println(nd);
//输出 -2.0```
** setScale **的第⼀个参数是保留的⼩数位数,第⼆个参数是舍⼊模式。可选的舍⼊模式有:
**HALF_EVEN**, 也就是银⾏家⽅式;
**HALF_UP**, 四舍五⼊;
**HALF_DOWN**, 五舍六⼊;
**CEILING、FLOOR**, 向正⽆穷、负⽆穷⽅向;
**UP、DOWN***, 向零和远离零;
**UNNECESSARY**, 断⾔舍⼊后的值和原值相等,也就是不需要舍⼊。如果断⾔错了,抛出**ArithmeticException**异常。先写到这,⽐较粗糙,但是希望你有所收获吧。欢迎讨论,有话好好说(╰( ̄▽ ̄)╭)

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。