Skip to content

Commit 313e2cb

Browse files
committed
py: int: fix floor divide to be exactly the same as python
1 parent 0dce941 commit 313e2cb

File tree

3 files changed

+169
-133
lines changed

3 files changed

+169
-133
lines changed

‎py/bigint.go‎

Lines changed: 35 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -214,74 +214,66 @@ func (a *BigInt) M__itruediv__(other Object) (Object, error){
214214
}
215215

216216
func (a*BigInt) M__floordiv__(otherObject) (Object, error){
217-
ifb, ok:=convertToBigInt(other); ok{
218-
return (*BigInt)(new(big.Int).Quo((*big.Int)(a), (*big.Int)(b))).MaybeInt(), nil
219-
}
220-
returnNotImplemented, nil
217+
result, _, err:=a.M__divmod__(other)
218+
returnresult, err
221219
}
222220

223221
func (a*BigInt) M__rfloordiv__(otherObject) (Object, error){
224-
ifb, ok:=convertToBigInt(other); ok{
225-
if (*big.Int)(a).Sign() ==0{
226-
returnnil, divisionByZero
227-
}
228-
return (*BigInt)(new(big.Int).Quo((*big.Int)(b), (*big.Int)(a))).MaybeInt(), nil
229-
}
230-
returnNotImplemented, nil
222+
result, _, err:=a.M__rdivmod__(other)
223+
returnresult, err
231224
}
232225

233226
func (a*BigInt) M__ifloordiv__(otherObject) (Object, error){
234-
returna.M__floordiv__(other)
227+
result, _, err:=a.M__divmod__(other)
228+
returnresult, err
235229
}
236230

237231
func (a*BigInt) M__mod__(otherObject) (Object, error){
238-
ifb, ok:=convertToBigInt(other); ok{
239-
if (*big.Int)(b).Sign() ==0{
240-
returnnil, divisionByZero
241-
}
242-
return (*BigInt)(new(big.Int).Rem((*big.Int)(a), (*big.Int)(b))).MaybeInt(), nil
243-
}
244-
returnNotImplemented, nil
232+
_, result, err:=a.M__divmod__(other)
233+
returnresult, err
245234
}
246235

247236
func (a*BigInt) M__rmod__(otherObject) (Object, error){
248-
ifb, ok:=convertToBigInt(other); ok{
249-
if (*big.Int)(a).Sign() ==0{
250-
returnnil, divisionByZero
251-
}
252-
return (*BigInt)(new(big.Int).Rem((*big.Int)(b), (*big.Int)(a))).MaybeInt(), nil
253-
}
254-
returnNotImplemented, nil
237+
_, result, err:=a.M__rdivmod__(other)
238+
returnresult, err
255239
}
256240

257241
func (a*BigInt) M__imod__(otherObject) (Object, error){
258-
returna.M__mod__(other)
242+
_, result, err:=a.M__divmod__(other)
243+
returnresult, err
244+
}
245+
246+
func (a*BigInt) divMod(b*BigInt) (Object, Object, error){
247+
if (*big.Int)(b).Sign() ==0{
248+
returnnil, nil, divisionByZero
249+
}
250+
r:=new(big.Int)
251+
q:=new(big.Int)
252+
q.QuoRem((*big.Int)(a), (*big.Int)(b), r)
253+
// Implement floor division
254+
negativeResult:= (*big.Int)(a).Sign() <0
255+
if (*big.Int)(b).Sign() <0{
256+
negativeResult=!negativeResult
257+
}
258+
ifnegativeResult&&r.Sign() !=0{
259+
q.Sub(q, (*big.Int)(bigInt1))
260+
r.Add(r, (*big.Int)(b))
261+
}
262+
return (*BigInt)(q).MaybeInt(), (*BigInt)(r).MaybeInt(), nil
259263
}
260264

261265
func (a*BigInt) M__divmod__(otherObject) (Object, Object, error){
262266
ifb, ok:=convertToBigInt(other); ok{
263-
if (*big.Int)(b).Sign() ==0{
264-
returnnil, nil, divisionByZero
265-
}
266-
r:=new(big.Int)
267-
q:=new(big.Int)
268-
q.QuoRem((*big.Int)(a), (*big.Int)(b), r)
269-
return (*BigInt)(q).MaybeInt(), (*BigInt)(r).MaybeInt(), nil
267+
returna.divMod(b)
270268
}
271-
returnNotImplemented, None, nil
269+
returnNotImplemented, NotImplemented, nil
272270
}
273271

274272
func (a*BigInt) M__rdivmod__(otherObject) (Object, Object, error){
275273
ifb, ok:=convertToBigInt(other); ok{
276-
if (*big.Int)(a).Sign() ==0{
277-
returnnil, nil, divisionByZero
278-
}
279-
r:=new(big.Int)
280-
q:=new(big.Int)
281-
q.QuoRem((*big.Int)(b), (*big.Int)(a), r)
282-
return (*BigInt)(q).MaybeInt(), (*BigInt)(r).MaybeInt(), nil
274+
returnb.divMod(a)
283275
}
284-
returnNotImplemented, None, nil
276+
returnNotImplemented, NotImplemented, nil
285277
}
286278

287279
func (a*BigInt) M__pow__(other, modulusObject) (Object, error){

‎py/int.go‎

Lines changed: 34 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -406,77 +406,65 @@ func (a Int) M__itruediv__(other Object) (Object, error){
406406
}
407407

408408
func (aInt) M__floordiv__(otherObject) (Object, error){
409-
ifb, ok:=convertToInt(other); ok{
410-
ifb==0{
411-
returnnil, divisionByZero
412-
}
413-
// Can't overflow
414-
returnInt(a/b), nil
415-
}
416-
returnNotImplemented, nil
409+
result, _, err:=a.M__divmod__(other)
410+
returnresult, err
417411
}
418412

419413
func (aInt) M__rfloordiv__(otherObject) (Object, error){
420-
ifb, ok:=convertToInt(other); ok{
421-
ifa==0{
422-
returnnil, divisionByZero
423-
}
424-
// Can't overflow
425-
returnInt(b/a), nil
426-
}
427-
returnNotImplemented, nil
414+
result, _, err:=a.M__rdivmod__(other)
415+
returnresult, err
428416
}
429417

430418
func (aInt) M__ifloordiv__(otherObject) (Object, error){
431-
returna.M__floordiv__(other)
419+
result, _, err:=a.M__divmod__(other)
420+
returnresult, err
432421
}
433422

434423
func (aInt) M__mod__(otherObject) (Object, error){
435-
ifb, ok:=convertToInt(other); ok{
436-
ifb==0{
437-
returnnil, divisionByZero
438-
}
439-
// Can't overflow
440-
returnInt(a%b), nil
441-
}
442-
returnNotImplemented, nil
424+
_, result, err:=a.M__divmod__(other)
425+
returnresult, err
443426
}
444427

445428
func (aInt) M__rmod__(otherObject) (Object, error){
446-
ifb, ok:=convertToInt(other); ok{
447-
ifa==0{
448-
returnnil, divisionByZero
449-
}
450-
// Can't overflow
451-
returnInt(b%a), nil
452-
}
453-
returnNotImplemented, nil
429+
_, result, err:=a.M__rdivmod__(other)
430+
returnresult, err
454431
}
455432

456433
func (aInt) M__imod__(otherObject) (Object, error){
457-
returna.M__mod__(other)
434+
_, result, err:=a.M__divmod__(other)
435+
returnresult, err
436+
}
437+
438+
func (aInt) divMod(bInt) (Object, Object, error){
439+
ifb==0{
440+
returnnil, nil, divisionByZero
441+
}
442+
// Can't overflow
443+
result, remainder:=Int(a/b), Int(a%b)
444+
// Implement floor division
445+
negativeResult:= (a<0)
446+
ifb<0{
447+
negativeResult=!negativeResult
448+
}
449+
ifnegativeResult&&remainder!=0{
450+
result-=1
451+
remainder+=b
452+
}
453+
returnresult, remainder, nil
458454
}
459455

460456
func (aInt) M__divmod__(otherObject) (Object, Object, error){
461457
ifb, ok:=convertToInt(other); ok{
462-
ifb==0{
463-
returnnil, nil, divisionByZero
464-
}
465-
// Can't overflow
466-
returnInt(a/b), Int(a%b), nil
458+
returna.divMod(b)
467459
}
468-
returnNotImplemented, None, nil
460+
returnNotImplemented, NotImplemented, nil
469461
}
470462

471463
func (aInt) M__rdivmod__(otherObject) (Object, Object, error){
472464
ifb, ok:=convertToInt(other); ok{
473-
ifa==0{
474-
returnnil, nil, divisionByZero
475-
}
476-
// Can't overflow
477-
returnInt(b/a), Int(b%a), nil
465+
returnb.divMod(a)
478466
}
479-
returnNotImplemented, None, nil
467+
returnNotImplemented, NotImplemented, nil
480468
}
481469

482470
func (aInt) M__pow__(other, modulusObject) (Object, error){

‎py/tests/int.py‎

Lines changed: 100 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -202,19 +202,77 @@ def approxEqual(a, b):
202202
approxEqual((8320894759108355333/688889843982879461528409053334), 1.2078701452470752e-11)
203203
approxEqual((647075625851211057828684328038/-326063662711018305247049652642), -1.9845070145847477)
204204

205-
# FIXME
206-
# doc='binop //'
207-
# assert (5744409969029584448//-1220411214895984398) == -5
208-
# assert (801848568806426077475668423535//-8085312908136062722) == -99173473918
209-
# assert (-5721542802125298347//-987715757830780227623113033880) == 0
210-
# assert (457897615381227167341108005859//-353379489795893751557547859364) == -2
211-
212-
# FIXME
213-
#doc='binop %'
214-
# assert (7341566843809298600%3978427562660778191) == 3363139281148520409
215-
# assert (294375077667396199949508874162%7786366607165572976) == 345835433804354002
216-
# assert (6316821303028268687%-707212250464589439185037502466) == -707212250458272617882009233779
217-
# assert (-119459441634706255601601571546%17130399946665545258117887219) == 453357991952561205223638987
205+
doc='Int divide signs'
206+
assert (123//20) ==6
207+
assert (123//-20) ==-7
208+
assert (-123//20) ==-7
209+
assert (-123//-20) ==6
210+
assert (123%20) ==3
211+
assert (123%-20) ==-17
212+
assert (-123%20) ==17
213+
assert (-123%-20) ==-3
214+
215+
doc='Int divide signs exact'
216+
assert (200//20) ==10
217+
assert (200//-20) ==-10
218+
assert (-200//20) ==-10
219+
assert (-200//-20) ==10
220+
assert (200%20) ==0
221+
assert (200%-20) ==0
222+
assert (-200%20) ==0
223+
assert (-200%-20) ==0
224+
225+
doc='Int divide zero'
226+
assert (200//201) ==0
227+
assert (200//-201) ==-1
228+
assert (-200//201) ==-1
229+
assert (-200//-201) ==0
230+
assert (200%201) ==200
231+
assert (200%-201) ==-1
232+
assert (-200%201) ==1
233+
assert (-200%-201) ==-200
234+
235+
doc='BigInt divide zero'
236+
assert (2000000000000000000000//2000000000000000000001) ==0
237+
assert (2000000000000000000000//-2000000000000000000001) ==-1
238+
assert (-2000000000000000000000//2000000000000000000001) ==-1
239+
assert (-2000000000000000000000//-2000000000000000000001) ==0
240+
assert (2000000000000000000000%2000000000000000000001) ==2000000000000000000000
241+
assert (2000000000000000000000%-2000000000000000000001) ==-1
242+
assert (-2000000000000000000000%2000000000000000000001) ==1
243+
assert (-2000000000000000000000%-2000000000000000000001) ==-2000000000000000000000
244+
245+
doc='BigInt divide signs'
246+
assert (1000000000000000000000000000001//100000000000000000001) ==9999999999
247+
assert (1000000000000000000000000000001//-100000000000000000001) ==-10000000000
248+
assert (-1000000000000000000000000000001//100000000000000000001) ==-10000000000
249+
assert (-1000000000000000000000000000001//-100000000000000000001) ==9999999999
250+
assert (1000000000000000000000000000001%100000000000000000001) ==99999999990000000002
251+
assert (1000000000000000000000000000001%-100000000000000000001) ==-9999999999
252+
assert (-1000000000000000000000000000001%100000000000000000001) ==9999999999
253+
assert (-1000000000000000000000000000001%-100000000000000000001) ==-99999999990000000002
254+
255+
doc='BigInt divide signs equal'
256+
assert (1000000000000000000000000000000//100000000000000000000) ==10000000000
257+
assert (1000000000000000000000000000000//-100000000000000000000) ==-10000000000
258+
assert (-1000000000000000000000000000000//100000000000000000000) ==-10000000000
259+
assert (-1000000000000000000000000000000//-100000000000000000000) ==10000000000
260+
assert (1000000000000000000000000000000%100000000000000000000) ==0
261+
assert (1000000000000000000000000000000%-100000000000000000000) ==0
262+
assert (-1000000000000000000000000000000%100000000000000000000) ==0
263+
assert (-1000000000000000000000000000000%-100000000000000000000) ==0
264+
265+
doc='binop //'
266+
assert (5744409969029584448//-1220411214895984398) ==-5
267+
assert (801848568806426077475668423535//-8085312908136062722) ==-99173473918
268+
assert (-5721542802125298347//-987715757830780227623113033880) ==0
269+
assert (457897615381227167341108005859//-353379489795893751557547859364) ==-2
270+
271+
doc='binop %'
272+
assert (7341566843809298600%3978427562660778191) ==3363139281148520409
273+
assert (294375077667396199949508874162%7786366607165572976) ==345835433804354002
274+
assert (6316821303028268687%-707212250464589439185037502466) ==-707212250458272617882009233779
275+
assert (-119459441634706255601601571546%17130399946665545258117887219) ==453357991952561205223638987
218276

219277
doc='binop &'
220278
assert (-6956530093671002017&-1100238534807351779) ==-8056622384673947619
@@ -326,35 +384,33 @@ def approxEqual(a, b):
326384
a/=-705476577911651649854533260835
327385
approxEqual(a, 0.9120485356446241)
328386

329-
# FIXME
330-
#doc='augop //'
331-
# a = -2955145545873784447
332-
# a //= -8398154603067315189
333-
# assert a == 0
334-
# a = 764874707978666366468709717939
335-
# a //= -637453031923767022
336-
# assert a == -1199891866026
337-
# a = -3225133016360684087
338-
# a //= -106830573980181067612866984034
339-
# assert a == 0
340-
# a = -1017486275496211203702167393
341-
# a //= 707873786594465355113033731247
342-
# assert a == -1
343-
344-
# FIXME
345-
# doc='augop %'
346-
# a = -4898359889955701722
347-
# a %= 2586537256564406544
348-
# assert a == 274714623173111366
349-
# a = 165600857868102801319021818388
350-
# a %= -5550996453372617970
351-
# assert a == -525692049140908922
352-
# a = -1667139790609035866
353-
# a %= 132512297800301099457101240885
354-
# assert a == 132512297798633959666492205019
355-
# a = 1223018728310354788098388057
356-
# a %= 756727576419043673398940776835
357-
# assert a == 1223018728310354788098388057
387+
doc='augop //'
388+
a=-2955145545873784447
389+
a//=-8398154603067315189
390+
asserta==0
391+
a=764874707978666366468709717939
392+
a//=-637453031923767022
393+
asserta==-1199891866026
394+
a=-3225133016360684087
395+
a//=-106830573980181067612866984034
396+
asserta==0
397+
a=-1017486275496211203702167393
398+
a//=707873786594465355113033731247
399+
asserta==-1
400+
401+
doc='augop %'
402+
a=-4898359889955701722
403+
a%=2586537256564406544
404+
asserta==274714623173111366
405+
a=165600857868102801319021818388
406+
a%=-5550996453372617970
407+
asserta==-525692049140908922
408+
a=-1667139790609035866
409+
a%=132512297800301099457101240885
410+
asserta==132512297798633959666492205019
411+
a=1223018728310354788098388057
412+
a%=756727576419043673398940776835
413+
asserta==1223018728310354788098388057
358414

359415
doc='augop &'
360416
a=-926347478023783305
@@ -401,8 +457,8 @@ def approxEqual(a, b):
401457
# FIXME
402458
# powmod
403459
# divmod
404-
# lsl
405-
# lsr
460+
# <<
461+
# >>
406462
# round
407463
# **
408464
# **=

0 commit comments

Comments
(0)