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__(other Object) (Object, error) {
217-
if b, ok := convertToBigInt(other); ok {
218-
return (*BigInt)(new(big.Int).Quo((*big.Int)(a), (*big.Int)(b))).MaybeInt(), nil
219-
}
220-
return NotImplemented, nil
217+
result, _, err := a.M__divmod__(other)
218+
return result, err
221219
}
222220

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

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

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

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

257241
func (a *BigInt) M__imod__(other Object) (Object, error) {
258-
return a.M__mod__(other)
242+
_, result, err := a.M__divmod__(other)
243+
return result, err
244+
}
245+
246+
func (a *BigInt) divMod(b *BigInt) (Object, Object, error) {
247+
if (*big.Int)(b).Sign() == 0 {
248+
return nil, 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+
if negativeResult && 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__(other Object) (Object, Object, error) {
262266
if b, ok := convertToBigInt(other); ok {
263-
if (*big.Int)(b).Sign() == 0 {
264-
return nil, 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+
return a.divMod(b)
270268
}
271-
return NotImplemented, None, nil
269+
return NotImplemented, NotImplemented, nil
272270
}
273271

274272
func (a *BigInt) M__rdivmod__(other Object) (Object, Object, error) {
275273
if b, ok := convertToBigInt(other); ok {
276-
if (*big.Int)(a).Sign() == 0 {
277-
return nil, 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+
return b.divMod(a)
283275
}
284-
return NotImplemented, None, nil
276+
return NotImplemented, NotImplemented, nil
285277
}
286278

287279
func (a *BigInt) M__pow__(other, modulus Object) (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 (a Int) M__floordiv__(other Object) (Object, error) {
409-
if b, ok := convertToInt(other); ok {
410-
if b == 0 {
411-
return nil, divisionByZero
412-
}
413-
// Can't overflow
414-
return Int(a / b), nil
415-
}
416-
return NotImplemented, nil
409+
result, _, err := a.M__divmod__(other)
410+
return result, err
417411
}
418412

419413
func (a Int) M__rfloordiv__(other Object) (Object, error) {
420-
if b, ok := convertToInt(other); ok {
421-
if a == 0 {
422-
return nil, divisionByZero
423-
}
424-
// Can't overflow
425-
return Int(b / a), nil
426-
}
427-
return NotImplemented, nil
414+
result, _, err := a.M__rdivmod__(other)
415+
return result, err
428416
}
429417

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

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

445428
func (a Int) M__rmod__(other Object) (Object, error) {
446-
if b, ok := convertToInt(other); ok {
447-
if a == 0 {
448-
return nil, divisionByZero
449-
}
450-
// Can't overflow
451-
return Int(b % a), nil
452-
}
453-
return NotImplemented, nil
429+
_, result, err := a.M__rdivmod__(other)
430+
return result, err
454431
}
455432

456433
func (a Int) M__imod__(other Object) (Object, error) {
457-
return a.M__mod__(other)
434+
_, result, err := a.M__divmod__(other)
435+
return result, err
436+
}
437+
438+
func (a Int) divMod(b Int) (Object, Object, error) {
439+
if b == 0 {
440+
return nil, 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+
if b < 0 {
447+
negativeResult = !negativeResult
448+
}
449+
if negativeResult && remainder != 0 {
450+
result -= 1
451+
remainder += b
452+
}
453+
return result, remainder, nil
458454
}
459455

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

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

482470
func (a Int) M__pow__(other, modulus Object) (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+
assert a == 0
391+
a = 764874707978666366468709717939
392+
a //= -637453031923767022
393+
assert a == -1199891866026
394+
a = -3225133016360684087
395+
a //= -106830573980181067612866984034
396+
assert a == 0
397+
a = -1017486275496211203702167393
398+
a //= 707873786594465355113033731247
399+
assert a == -1
400+
401+
doc='augop %'
402+
a = -4898359889955701722
403+
a %= 2586537256564406544
404+
assert a == 274714623173111366
405+
a = 165600857868102801319021818388
406+
a %= -5550996453372617970
407+
assert a == -525692049140908922
408+
a = -1667139790609035866
409+
a %= 132512297800301099457101240885
410+
assert a == 132512297798633959666492205019
411+
a = 1223018728310354788098388057
412+
a %= 756727576419043673398940776835
413+
assert a == 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)