Skip to content

Commit 0e6bb4c

Browse files
committed
py: implement round() for int/long, float() and complex()
1 parent 2bc7a53 commit 0e6bb4c

File tree

5 files changed

+163
-33
lines changed

5 files changed

+163
-33
lines changed

py/bigint.go

Lines changed: 21 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ func (o *BigInt) Type() *Type {
2020
var (
2121
bigInt0 = (*BigInt)(big.NewInt(0))
2222
bigInt1 = (*BigInt)(big.NewInt(1))
23+
bigInt10 = (*BigInt)(big.NewInt(10))
2324
bigIntMin = (*BigInt)(big.NewInt(IntMin))
2425
bigIntMax = (*BigInt)(big.NewInt(IntMax))
2526
)
@@ -456,15 +457,28 @@ func (a *BigInt) M__complex__() (Object, error) {
456457

457458
func (a *BigInt) M__round__(digits Object) (Object, error) {
458459
if b, ok := convertToBigInt(digits); ok {
459-
bb, err := b.GoInt()
460-
if err != nil {
461-
return nil, err
462-
}
463-
if bb >= 0 {
460+
if (*big.Int)(b).Sign() >= 0 {
464461
return a, nil
465462
}
466-
// FIXME return a - (a % 10**(-bb))
467-
return nil, NotImplementedError
463+
negative := false
464+
r := new(big.Int).Set((*big.Int)(a))
465+
if r.Sign() < 0 {
466+
r.Neg(r)
467+
negative = true
468+
}
469+
negB := new(big.Int).Neg((*big.Int)(b))
470+
scale := new(big.Int).Exp((*big.Int)(bigInt10), negB, nil)
471+
digits := new(big.Int).Mod(r, scale)
472+
r.Sub(r, digits)
473+
// Round
474+
digits.Lsh(digits, 1)
475+
if digits.Cmp(scale) >= 0 {
476+
r.Add(r, scale)
477+
}
478+
if negative {
479+
r.Neg(r)
480+
}
481+
return (*BigInt)(r), nil
468482
}
469483
return cantConvert(digits, "int")
470484
}

py/complex.go

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import (
77
"math/cmplx"
88
)
99

10-
var ComplexType = NewType("complex64", "complex(real[, imag]) -> complex number\n\nCreate a complex number from a real part and an optional imaginary part.\nThis is equivalent to (real + imag*1j) where imag defaults to 0.")
10+
var ComplexType = ObjectType.NewType("complex64", "complex(real[, imag]) -> complex number\n\nCreate a complex number from a real part and an optional imaginary part.\nThis is equivalent to (real + imag*1j) where imag defaults to 0.", ComplexNew, nil)
1111

1212
type Complex complex128
1313

@@ -16,6 +16,25 @@ func (o Complex) Type() *Type {
1616
return ComplexType
1717
}
1818

19+
// ComplexNew
20+
func ComplexNew(metatype *Type, args Tuple, kwargs StringDict) (Object, error) {
21+
var realObj Object = Float(0)
22+
var imagObj Object = Float(0)
23+
err := ParseTupleAndKeywords(args, kwargs, "|OO", []string{"real", "imag"}, &realObj, &imagObj)
24+
if err != nil {
25+
return nil, err
26+
}
27+
real, err := MakeFloat(realObj)
28+
if err != nil {
29+
return nil, err
30+
}
31+
imag, err := MakeFloat(imagObj)
32+
if err != nil {
33+
return nil, err
34+
}
35+
return Complex(complex(real.(Float), imag.(Float))), nil
36+
}
37+
1938
// Convert an Object to an Complex
2039
//
2140
// Retrurns ok as to whether the conversion worked or not

py/float.go

Lines changed: 34 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,16 @@ package py
55
import (
66
"math"
77
"math/big"
8+
"strconv"
89
)
910

10-
var FloatType = NewType("float", "float(x) -> floating point number\n\nConvert a string or number to a floating point number, if possible.")
11+
var FloatType = ObjectType.NewType("float", "float(x) -> floating point number\n\nConvert a string or number to a floating point number, if possible.", FloatNew, nil)
12+
13+
// Bits of precision in a float64
14+
const (
15+
float64precision = 53
16+
float64MaxExponent = 1023
17+
)
1118

1219
type Float float64
1320

@@ -16,11 +23,32 @@ func (o Float) Type() *Type {
1623
return FloatType
1724
}
1825

19-
// Bits of precision in a float64
20-
const (
21-
float64precision = 53
22-
float64MaxExponent = 1023
23-
)
26+
// FloatNew
27+
func FloatNew(metatype *Type, args Tuple, kwargs StringDict) (Object, error) {
28+
var xObj Object = Float(0)
29+
err := ParseTupleAndKeywords(args, kwargs, "|O", []string{"x"}, &xObj)
30+
if err != nil {
31+
return nil, err
32+
}
33+
// Special case converting string types
34+
switch x := xObj.(type) {
35+
// FIXME Bytearray
36+
case Bytes:
37+
return FloatFromString(string(x))
38+
case String:
39+
return FloatFromString(string(x))
40+
}
41+
return MakeFloat(xObj)
42+
}
43+
44+
// FloatFromString turns a string into a Float
45+
func FloatFromString(str string) (Object, error) {
46+
f, err := strconv.ParseFloat(str, 64)
47+
if err != nil {
48+
return nil, ExceptionNewf(ValueError, "could not convert string to float: '%s'", str)
49+
}
50+
return Float(f), nil
51+
}
2452

2553
// Arithmetic
2654

py/int.go

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
package py
44

55
import (
6+
"math"
67
"math/big"
78
"strconv"
89
"strings"
@@ -599,8 +600,27 @@ func (a Int) M__round__(digits Object) (Object, error) {
599600
if b >= 0 {
600601
return a, nil
601602
}
602-
// FIXME return a - (a % 10**(-bb))
603-
return nil, NotImplementedError
603+
// Promote to BigInt if 10**-b > 2**63
604+
if b <= -19 {
605+
return (*BigInt)(big.NewInt(int64(a))).M__round__(digits)
606+
}
607+
negative := false
608+
r := a
609+
if r < 0 {
610+
r = -r
611+
negative = true
612+
}
613+
scale := Int(math.Pow(10, float64(-b)))
614+
digits := r % scale
615+
r -= digits
616+
// Round
617+
if 2*digits >= scale {
618+
r += scale
619+
}
620+
if negative {
621+
r = -r
622+
}
623+
return r, nil
604624
}
605625
return cantConvert(digits, "int")
606626
}

py/tests/int.py

Lines changed: 66 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -155,19 +155,15 @@ def assertRaises(expecting, s, base=None):
155155
assert (~-6763809348657986856) == 6763809348657986855
156156
assert (~-874993321372974196107431462962) == 874993321372974196107431462961
157157

158-
#FIXME
159-
#doc='unop float'
160-
#assert (float(-6450284370390530229)) == -6.45028437039053e+18
161-
#assert (float(499622087565400960139933324516)) == 4.99622087565401e+29
162-
#assert (float(-2669664172783636500)) == -2.6696641727836365e+18
163-
#assert (float(586226139343958088885818537791)) == 5.862261393439581e+29
164-
165-
# FIXME
166-
# doc='unop complex'
167-
# assert (complex(8933717091386849423)) == (8.933717091386849e+18+0j)
168-
# assert (complex(-112003440633045743638450994095)) == (-1.1200344063304574e+29+0j)
169-
# assert (complex(-1231948596602428130)) == (-1.2319485966024282e+18+0j)
170-
# assert (complex(-870659418246097554269256403682)) == (-8.706594182460975e+29+0j)
158+
doc='unop float'
159+
assert (float(-6450284370390530229)) == -6.45028437039053e+18
160+
assert (float(499622087565400960139933324516)) == 4.99622087565401e+29
161+
assert (float(-2669664172783636500)) == -2.6696641727836365e+18
162+
assert (float(586226139343958088885818537791)) == 5.862261393439581e+29
163+
164+
doc='unop complex'
165+
assert (complex(8933717091386849423, -1231948596602428130)) == (8.933717091386849e+18+-1.2319485966024282e+18j)
166+
assert (complex(-112003440633045743638450994095, -870659418246097554269256403682)) == (-1.1200344063304574e+29+-8.706594182460975e+29j)
171167

172168
doc='unop int'
173169
assert (int(2996679482204208157)) == 2996679482204208157
@@ -548,10 +544,63 @@ def approxEqual(a, b):
548544
a **= 100000000000000000001
549545
assert a == -1
550546

551-
# FIXME
552-
# pow
553-
# divmod
554-
# round
547+
doc="pow(x,y)"
548+
assert pow(2,10) == 1024
549+
assert pow(-2,10) == 1024
550+
approxEqual(pow(2,-10), 0.0009765625)
551+
approxEqual(pow(-2,-10), 0.0009765625)
552+
assert pow(3,100) == 515377520732011331036461129765621272702107522001
553+
approxEqual(pow(515377520732011331036461129765621272702107522001,-1), 1.9403252174826328e-48)
554+
assert pow(-1,100000000000000000000) == 1
555+
assert pow(-1,100000000000000000001) == -1
556+
557+
doc="pow(x,y,z)"
558+
assert pow(1938019302983,283019283019238,91283091283012938) == 90917306668848727
559+
pow(193801930298311111111111111111111,28301928301923822222222222222222222,9128309128301293822222222222222222222) == 2810220059867374937460899006752893533
560+
assert pow(True, 10) == 1
561+
try:
562+
pow(1,-1,1)
563+
except TypeError:
564+
pass
565+
else:
566+
assert False, "TypeError not raised"
567+
568+
doc="round"
569+
assert round(12345678, 10) == 12345678
570+
assert round(12345678, 0) == 12345678
571+
assert round(12345678, -2) == 12345700
572+
assert round(12345678, -4) == 12350000
573+
assert round(12345678, -6) == 12000000
574+
assert round(12345678, -8) == 0
575+
assert round(9223372036854775807, -17) == 9200000000000000000
576+
assert round(9223372036854775807, -18) == 9000000000000000000
577+
assert round(9223372036854775807, -19) == 10000000000000000000
578+
579+
assert round(-12345678, 10) == -12345678
580+
assert round(-12345678, 0) == -12345678
581+
assert round(-12345678, -2) == -12345700
582+
assert round(-12345678, -4) == -12350000
583+
assert round(-12345678, -6) == -12000000
584+
assert round(-12345678, -8) == 0
585+
assert round(-9223372036854775808, -17) == -9200000000000000000
586+
assert round(-9223372036854775808, -18) == -9000000000000000000
587+
assert round(-9223372036854775808, -19) == -10000000000000000000
588+
589+
assert round(123456789012345678901, 10) == 123456789012345678901
590+
assert round(123456789012345678901, 0) == 123456789012345678901
591+
assert round(123456789012345678901, -2) == 123456789012345678900
592+
assert round(123456789012345678901, -4) == 123456789012345680000
593+
assert round(123456789012345678901, -6) == 123456789012346000000
594+
assert round(123456789012345678901,-19) == 120000000000000000000
595+
assert round(123456789012345678901,-21) == 0
596+
597+
assert round(-123456789012345678901, 10) == -123456789012345678901
598+
assert round(-123456789012345678901, 0) == -123456789012345678901
599+
assert round(-123456789012345678901, -2) == -123456789012345678900
600+
assert round(-123456789012345678901, -4) == -123456789012345680000
601+
assert round(-123456789012345678901, -6) == -123456789012346000000
602+
assert round(-123456789012345678901,-19) == -120000000000000000000
603+
assert round(-123456789012345678901,-21) == 0
555604

556605
doc="finished"
557606

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy