Skip to content
Projects
Groups
Snippets
Help
Loading...
Sign in
Toggle navigation
G
golang
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Commits
Issue Boards
Open sidebar
go
golang
Commits
543226e8
Commit
543226e8
authored
Jun 19, 2008
by
Robert Griesemer
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
- added large integer arithmetic package and test cases
SVN=123486
parent
3df8e0a1
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
767 additions
and
0 deletions
+767
-0
golden.out
test/golden.out
+12
-0
integer.go
test/integer.go
+618
-0
test_integer.go
test/test_integer.go
+137
-0
No files found.
test/golden.out
View file @
543226e8
...
...
@@ -21,6 +21,8 @@ hello, world
=========== ./int_lit.go
=========== ./integer.go
=========== ./iota.go
=========== ./literal.go
...
...
@@ -53,6 +55,16 @@ test0.go:47: illegal types for operand: AS
({})
BUG: known to fail incorrectly
=========== ./test_integer.go
TestConv
TestAdd
TestSub
TestMul
TestDiv
TestMod
TestFact
PASSED
=========== ./turing.go
Hello World!
...
...
test/integer.go
0 → 100755
View file @
543226e8
// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package
Integer
const
ValueLen
=
1000
;
type
Word
uint32
type
Value
*
[
ValueLen
]
Word
type
IntegerImpl
struct
{
val
Value
}
type
Integer
*
IntegerImpl
export
IntegerImpl
,
Integer
const
N
=
4
;
const
H
=
1
const
L
=
28
;
const
M
=
1
<<
L
-
1
;
// ----------------------------------------------------------------------------
// Support
// TODO What are we going to about asserts?
func
ASSERT
(
p
bool
)
{
if
!
p
{
panic
"ASSERT failed"
;
}
}
func
CHECK
(
p
bool
)
{
if
!
p
{
panic
"CHECK failed"
;
}
}
func
UNIMPLEMENTED
(
s
string
)
{
panic
"UNIMPLEMENTED: "
,
s
;
}
// ----------------------------------------------------------------------------
//
// TODO "len" is a reserved word at the moment - I think that's wrong
func
len_
(
x
Value
)
int
{
l
:=
int
(
x
[
0
]);
if
l
<
0
{
return
-
l
;
}
return
l
;
}
func
set_len
(
x
Value
,
len_
int
)
{
x
[
0
]
=
Word
(
len_
);
}
func
alloc
(
len_
int
)
Value
{
ASSERT
(
len_
>=
0
);
z
:=
new
([
ValueLen
]
Word
);
set_len
(
z
,
len_
);
return
z
;
}
func
sign
(
x
Value
)
bool
{
return
int
(
x
[
0
])
<
0
;
}
func
zero
(
x
Value
)
bool
{
return
x
[
0
]
==
0
;
}
func
neg
(
x
Value
)
{
x
[
0
]
=
Word
(
-
int
(
x
[
0
]));
}
// ----------------------------------------------------------------------------
// Unsigned ops
func
make
(
x
int
)
Value
;
func
Update
(
x
Word
)
(
z
,
c
Word
)
{
// z = x & M;
// c = x >> L;
return
x
&
M
,
x
>>
L
;
}
func
uadd
(
x
,
y
Value
)
Value
{
xl
:=
len_
(
x
);
yl
:=
len_
(
y
);
if
xl
<
yl
{
return
uadd
(
y
,
x
);
}
ASSERT
(
xl
>=
yl
);
z
:=
alloc
(
xl
+
1
);
i
:=
0
;
c
:=
Word
(
0
);
for
i
<
yl
{
z
[
i
+
H
],
c
=
Update
(
x
[
i
+
H
]
+
y
[
i
+
H
]
+
c
);
i
++
;
}
for
i
<
xl
{
z
[
i
+
H
],
c
=
Update
(
x
[
i
+
H
]
+
c
);
i
++
;
}
if
c
!=
0
{
z
[
i
+
H
]
=
c
;
i
++
;
}
set_len
(
z
,
i
);
return
z
;
}
func
usub
(
x
,
y
Value
)
Value
{
xl
:=
len_
(
x
);
yl
:=
len_
(
y
);
if
xl
<
yl
{
return
uadd
(
y
,
x
);
}
ASSERT
(
xl
>=
yl
);
z
:=
alloc
(
xl
+
1
);
i
:=
0
;
c
:=
Word
(
0
);
for
i
<
yl
{
z
[
i
+
H
],
c
=
Update
(
x
[
i
+
H
]
-
y
[
i
+
H
]
+
c
);
i
++
;
}
for
i
<
xl
{
z
[
i
+
H
],
c
=
Update
(
x
[
i
+
H
]
+
c
);
i
++
;
}
ASSERT
(
c
==
0
);
// usub(x, y) must be called with x >= y
for
i
>
0
&&
z
[
i
-
1
+
H
]
==
0
{
i
--
;
}
set_len
(
z
,
i
);
return
z
;
}
// Computes x = x*a + c (in place) for "small" a's.
func
umul_add
(
x
Value
,
a
,
c
Word
)
Value
{
CHECK
(
0
<=
a
&&
a
<
(
1
<<
N
));
CHECK
(
0
<=
c
&&
c
<
(
1
<<
N
));
if
(
zero
(
x
)
||
a
==
0
)
&&
c
==
0
{
return
make
(
0
);
}
xl
:=
len_
(
x
);
z
:=
alloc
(
xl
+
1
);
i
:=
0
;
for
i
<
xl
{
z
[
i
+
H
],
c
=
Update
(
x
[
i
+
H
]
*
a
+
c
);
i
++
;
}
if
c
!=
0
{
z
[
i
+
H
]
=
c
;
i
++
;
}
set_len
(
z
,
i
);
return
z
;
}
// Computes x = x div d (in place) for "small" d's. Returns x mod d.
func
umod
(
x
Value
,
d
Word
)
Word
{
CHECK
(
0
<
d
&&
d
<
(
1
<<
N
));
xl
:=
len_
(
x
);
c
:=
Word
(
0
);
i
:=
xl
;
for
i
>
0
{
i
--
;
c
=
c
<<
L
+
x
[
i
+
H
];
q
:=
c
/
d
;
x
[
i
+
H
]
=
q
;
//x[i + H] = c / d; // BUG
c
=
c
%
d
;
}
if
xl
>
0
&&
x
[
xl
-
1
+
H
]
==
0
{
set_len
(
x
,
xl
-
1
);
}
return
c
;
}
// Returns z = (x * y) div B, c = (x * y) mod B.
func
umul1
(
x
,
y
Word
)
(
z
Word
,
c
Word
)
{
const
L2
=
(
L
+
1
)
>>
1
;
const
B2
=
1
<<
L2
;
const
M2
=
B2
-
1
;
x0
:=
x
&
M2
;
x1
:=
x
>>
L2
;
y0
:=
y
&
M2
;
y1
:=
y
>>
L2
;
z10
:=
x0
*
y0
;
z21
:=
x1
*
y0
+
x0
*
y1
+
(
z10
>>
L2
);
cc
:=
x1
*
y1
+
(
z21
>>
L2
);
zz
:=
((
z21
&
M2
)
<<
L2
)
|
(
z10
&
M2
);
return
zz
,
cc
}
func
umul
(
x
Value
,
y
Value
)
Value
{
if
zero
(
x
)
||
zero
(
y
)
{
return
make
(
0
);
}
xl
:=
len_
(
x
);
yl
:=
len_
(
y
);
if
xl
<
yl
{
return
umul
(
y
,
x
);
// for speed
}
ASSERT
(
xl
>=
yl
&&
yl
>
0
);
// initialize z
zl
:=
xl
+
yl
;
z
:=
alloc
(
zl
);
for
i
:=
0
;
i
<
zl
;
i
++
{
z
[
i
+
H
]
=
0
;
}
k
:=
0
;
for
j
:=
0
;
j
<
yl
;
j
++
{
d
:=
y
[
j
+
H
];
if
d
!=
0
{
k
=
j
;
c
:=
Word
(
0
);
for
i
:=
0
;
i
<
xl
;
i
++
{
// compute z[k + H] += x[i + H] * d + c;
t
:=
z
[
k
+
H
]
+
c
;
var
z1
Word
;
z1
,
c
=
umul1
(
x
[
i
+
H
],
d
);
t
+=
z1
;
z
[
k
+
H
]
=
t
&
M
;
c
+=
t
>>
L
;
k
++
;
}
if
c
!=
0
{
z
[
k
+
H
]
=
Word
(
c
);
k
++
;
}
}
}
set_len
(
z
,
k
);
return
z
;
}
func
ucmp
(
x
Value
,
y
Value
)
int
{
xl
:=
len_
(
x
);
yl
:=
len_
(
y
);
if
xl
!=
yl
||
xl
==
0
{
return
xl
-
yl
;
}
i
:=
xl
-
1
;
for
i
>
0
&&
x
[
i
+
H
]
==
y
[
i
+
H
]
{
i
--
;
}
return
int
(
x
[
i
+
H
])
-
int
(
y
[
i
+
H
]);
}
func
ulog
(
x
Value
)
int
{
xl
:=
len_
(
x
);
if
xl
==
0
{
return
0
;
}
n
:=
(
xl
-
1
)
*
L
;
for
t
:=
x
[
xl
-
1
+
H
];
t
!=
0
;
t
>>=
1
{
n
++
};
return
n
;
}
func
make
(
x
int
)
Value
{
if
x
==
0
{
z
:=
alloc
(
0
);
set_len
(
z
,
0
);
return
z
;
}
if
x
==
-
x
{
// smallest int
z
:=
alloc
(
2
);
z
[
0
+
H
]
=
0
;
z
[
1
+
H
]
=
1
;
set_len
(
z
,
-
2
);
return
z
;
}
z
:=
alloc
(
1
);
if
x
<
0
{
z
[
0
+
H
]
=
Word
(
-
x
);
set_len
(
z
,
-
1
);
}
else
{
z
[
0
+
H
]
=
Word
(
x
);
set_len
(
z
,
1
);
}
return
z
;
}
func
make_from_string
(
s
string
)
Value
{
// skip sign, if any
i
:=
0
;
if
len
(
s
)
>
0
&&
(
s
[
i
]
==
'-'
||
s
[
i
]
==
'+'
)
{
i
=
1
;
}
// read digits
x
:=
make
(
0
);
for
i
<
len
(
s
)
&&
'0'
<=
s
[
i
]
&&
s
[
i
]
<=
'9'
{
x
=
umul_add
(
x
,
10
,
Word
(
s
[
i
]
-
'0'
));
i
++
;
}
// read sign
if
len
(
s
)
>
0
&&
s
[
0
]
==
'-'
{
neg
(
x
);
}
return
x
;
}
// ----------------------------------------------------------------------------
// Creation
func
(
x
Integer
)
Init
(
val
Value
)
Integer
{
x
.
val
=
val
;
return
x
;
}
// ----------------------------------------------------------------------------
// Signed ops
func
add
(
x
Value
,
y
Value
)
Value
{
var
z
Value
;
if
sign
(
x
)
==
sign
(
y
)
{
// x + y == x + y
// (-x) + (-y) == -(x + y)
z
=
uadd
(
x
,
y
);
}
else
{
// x + (-y) == x - y == -(y - x)
// (-x) + y == y - x == -(x - y)
if
ucmp
(
x
,
y
)
>=
0
{
z
=
usub
(
x
,
y
);
}
else
{
z
=
usub
(
y
,
x
);
neg
(
z
);
}
}
if
sign
(
x
)
{
neg
(
z
);
}
return
z
;
}
func
sub
(
x
Value
,
y
Value
)
Value
{
var
z
Value
;
if
sign
(
x
)
!=
sign
(
y
)
{
// x - (-y) == x + y
// (-x) - y == -(x + y)
z
=
uadd
(
x
,
y
);
}
else
{
// x - y == x - y == -(y - x)
// (-x) - (-y) == y - x == -(x - y)
if
ucmp
(
x
,
y
)
>=
0
{
z
=
usub
(
x
,
y
);
}
else
{
z
=
usub
(
y
,
x
);
neg
(
z
);
}
}
if
sign
(
x
)
{
neg
(
z
);
}
return
z
;
}
func
mul
(
x
Value
,
y
Value
)
Value
{
// x * y == x * y
// x * (-y) == -(x * y)
// (-x) * y == -(x * y)
// (-x) * (-y) == x * y
z
:=
umul
(
x
,
y
);
if
sign
(
x
)
!=
sign
(
y
)
{
neg
(
z
);
}
return
z
;
}
func
mul_range
(
a
,
b
int
)
Value
{
if
a
>
b
{
return
make
(
1
)
};
if
a
==
b
{
return
make
(
a
)
};
if
a
+
1
==
b
{
return
mul
(
make
(
a
),
make
(
b
))
};
m
:=
(
a
+
b
)
>>
1
;
ASSERT
(
a
<=
m
&&
m
<
b
);
return
mul
(
mul_range
(
a
,
m
),
mul_range
(
m
+
1
,
b
));
}
func
fact
(
n
int
)
Value
{
return
mul_range
(
2
,
n
);
}
// Returns a copy of x with space for one extra digit.
func
copy
(
x
Value
)
Value
{
xl
:=
len_
(
x
);
z
:=
alloc
(
xl
+
1
);
// add space for one extra digit
for
i
:=
0
;
i
<
xl
;
i
++
{
z
[
i
+
H
]
=
x
[
i
+
H
];
}
set_len
(
z
,
xl
);
return
z
;
}
func
tostring
(
x
Value
)
string
{
// allocate string
// approx. length: 1 char for 3 bits
n
:=
ulog
(
x
)
/
3
+
3
;
// +1 (round up) +1 (sign) +1 (0 termination)
//s := new([]byte, n);
s
:=
new
([
100000
]
byte
);
// convert
z
:=
copy
(
x
);
i
:=
0
;
for
i
==
0
||
!
zero
(
z
)
{
s
[
i
]
=
byte
(
umod
(
z
,
10
)
+
'0'
);
i
++
;
};
if
sign
(
x
)
{
s
[
i
]
=
'-'
;
i
++
;
}
s
[
i
]
=
0
;
ASSERT
(
0
<
i
&&
i
<
n
);
// reverse in place
i
--
;
for
j
:=
0
;
j
<
i
;
j
++
{
t
:=
s
[
j
];
s
[
j
]
=
s
[
i
];
s
[
i
]
=
t
;
i
--
;
}
return
string
(
s
);
}
// ----------------------------------------------------------------------------
// Creation
export
FromInt
func
FromInt
(
v
int
)
Integer
{
return
new
(
IntegerImpl
)
.
Init
(
make
(
v
));
}
export
FromString
func
FromString
(
s
string
)
Integer
{
return
new
(
IntegerImpl
)
.
Init
(
make_from_string
(
s
));
}
// ----------------------------------------------------------------------------
// Arithmetic ops
func
(
x
Integer
)
neg
()
Integer
{
if
(
zero
(
x
.
val
))
{
return
new
(
IntegerImpl
)
.
Init
(
make
(
0
));
}
z
:=
copy
(
x
.
val
);
neg
(
z
);
return
new
(
IntegerImpl
)
.
Init
(
z
);
}
func
(
x
Integer
)
add
(
y
Integer
)
Integer
{
return
new
(
IntegerImpl
)
.
Init
(
add
(
x
.
val
,
y
.
val
));
}
func
(
x
Integer
)
sub
(
y
Integer
)
Integer
{
return
new
(
IntegerImpl
)
.
Init
(
sub
(
x
.
val
,
y
.
val
));
}
func
(
x
Integer
)
mul
(
y
Integer
)
Integer
{
return
new
(
IntegerImpl
)
.
Init
(
mul
(
x
.
val
,
y
.
val
));
}
func
(
x
Integer
)
quo
(
y
Integer
)
Integer
{
UNIMPLEMENTED
(
"quo"
);
return
nil
;
}
func
(
x
Integer
)
rem
(
y
Integer
)
Integer
{
UNIMPLEMENTED
(
"rem"
);
return
nil
;
}
func
(
x
Integer
)
div
(
y
Integer
)
Integer
{
UNIMPLEMENTED
(
"div"
);
return
nil
;
}
func
(
x
Integer
)
mod
(
y
Integer
)
Integer
{
UNIMPLEMENTED
(
"mod"
);
return
nil
;
}
// ----------------------------------------------------------------------------
// Arithmetic shifts
func
(
x
Integer
)
shl
(
s
uint
)
Integer
{
UNIMPLEMENTED
(
"shl"
);
return
nil
;
}
func
(
x
Integer
)
shr
(
s
uint
)
Integer
{
UNIMPLEMENTED
(
"shr"
);
return
nil
;
}
// ----------------------------------------------------------------------------
// Logical ops
func
(
x
Integer
)
inv
()
Integer
{
UNIMPLEMENTED
(
"inv"
);
return
nil
;
}
func
(
x
Integer
)
and
(
y
Integer
)
Integer
{
UNIMPLEMENTED
(
"and"
);
return
nil
;
}
func
(
x
Integer
)
or
(
y
Integer
)
Integer
{
UNIMPLEMENTED
(
"or"
);
return
nil
;
}
func
(
x
Integer
)
xor
(
y
Integer
)
Integer
{
UNIMPLEMENTED
(
"xor"
);
return
nil
;
}
// ----------------------------------------------------------------------------
// Comparisons
func
(
x
Integer
)
cmp
(
y
Integer
)
int
{
return
0
;
}
func
(
x
Integer
)
eql
(
y
Integer
)
bool
{
return
x
.
cmp
(
y
)
==
0
;
}
func
(
x
Integer
)
neq
(
y
Integer
)
bool
{
return
x
.
cmp
(
y
)
!=
0
;
}
func
(
x
Integer
)
lss
(
y
Integer
)
bool
{
return
x
.
cmp
(
y
)
<
0
;
}
func
(
x
Integer
)
leq
(
y
Integer
)
bool
{
return
x
.
cmp
(
y
)
<=
0
;
}
func
(
x
Integer
)
gtr
(
y
Integer
)
bool
{
return
x
.
cmp
(
y
)
>
0
;
}
func
(
x
Integer
)
geq
(
y
Integer
)
bool
{
return
x
.
cmp
(
y
)
>=
0
;
}
// ----------------------------------------------------------------------------
// Specials
export
Fact
func
Fact
(
n
int
)
Integer
{
return
new
(
IntegerImpl
)
.
Init
(
fact
(
n
));
}
func
(
x
Integer
)
ToString
()
string
{
return
tostring
(
x
.
val
);
}
test/test_integer.go
0 → 100644
View file @
543226e8
// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package
main
import
Integer
"integer"
type
Int
Integer
.
Integer
;
const
(
sa
=
"991"
;
sb
=
"2432902008176640000"
;
// 20!
sc
=
"93326215443944152681699238856266700490715968264381621468592963895217599993229915608941463976156518286253697920827223758251185210916864000000000000000000000000"
;
// 100!
)
var
(
m
,
z
,
p
,
a
,
b
,
c
,
a_a
,
a_b
,
a_c
,
b_b
,
b_c
,
c_c
,
a_b_c
Int
)
func
CHECK
(
p
bool
)
{
if
!
p
{
panic
"CHECK failed
\n
"
;
}
}
func
Init
()
{
m
=
Integer
.
FromInt
(
-
1
);
z
=
Integer
.
FromInt
(
0
);
p
=
Integer
.
FromInt
(
1
);
a
=
Integer
.
FromString
(
sa
);
b
=
Integer
.
FromString
(
sb
);
c
=
Integer
.
FromString
(
sc
);
a_a
=
Integer
.
FromInt
(
991
+
991
);
a_b
=
Integer
.
FromString
(
"2432902008176640991"
);
a_c
=
Integer
.
FromString
(
"93326215443944152681699238856266700490715968264381621468592963895217599993229915608941463976156518286253697920827223758251185210916864000000000000000000000991"
);
}
func
TestConv
()
{
print
"TestConv
\n
"
;
CHECK
(
a
.
eql
(
Integer
.
FromInt
(
991
)));
CHECK
(
b
.
eql
(
Integer
.
Fact
(
20
)));
CHECK
(
c
.
eql
(
Integer
.
Fact
(
100
)));
CHECK
(
a
.
ToString
()
==
sa
);
CHECK
(
b
.
ToString
()
==
sb
);
CHECK
(
c
.
ToString
()
==
sc
);
// also tested much via TestFact
}
func
TestAdd
()
{
print
"TestAdd
\n
"
;
CHECK
(
z
.
add
(
z
)
.
eql
(
z
));
CHECK
(
a
.
add
(
z
)
.
eql
(
a
));
CHECK
(
z
.
add
(
a
)
.
eql
(
a
));
CHECK
(
c
.
add
(
z
)
.
eql
(
c
));
CHECK
(
z
.
add
(
c
)
.
eql
(
c
));
CHECK
(
m
.
add
(
p
)
.
eql
(
z
));
CHECK
(
a
.
add
(
a
)
.
eql
(
a_a
));
CHECK
(
a
.
add
(
b
)
.
eql
(
a_b
));
CHECK
(
a
.
add
(
c
)
.
eql
(
a_c
));
// needs more
}
func
TestSub
()
{
print
"TestSub
\n
"
;
CHECK
(
z
.
sub
(
z
)
.
eql
(
z
));
CHECK
(
a
.
sub
(
z
)
.
eql
(
a
));
CHECK
(
z
.
sub
(
a
)
.
eql
(
a
.
neg
()));
CHECK
(
c
.
sub
(
z
)
.
eql
(
c
));
CHECK
(
z
.
sub
(
c
)
.
eql
(
c
.
neg
()));
CHECK
(
p
.
sub
(
m
)
.
eql
(
p
.
add
(
p
)));
CHECK
(
a
.
sub
(
a
)
.
eql
(
z
));
// needs more
}
func
TestMul
()
{
print
"TestMul
\n
"
;
// tested much via TestFact for now
}
func
TestDiv
()
{
print
"TestDiv
\n
"
;
// no div implemented yet
}
func
TestMod
()
{
print
"TestMod
\n
"
;
// no mod implemented yet
}
func
TestFact
()
{
print
"TestFact
\n
"
;
for
n
:=
990
;
n
<
1010
;
n
++
{
f
:=
Integer
.
Fact
(
n
);
CHECK
(
Integer
.
FromString
(
f
.
ToString
())
.
eql
(
f
));
}
}
func
main
()
{
Init
();
TestConv
();
TestAdd
();
TestSub
();
TestMul
();
TestDiv
();
TestMod
();
TestFact
();
print
"PASSED
\n
"
;
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment