aboutsummaryrefslogtreecommitdiff
path: root/bignum.h
blob: 67ae9027aa72aeeb77fe040e42aa6f836d8c5b7e (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
/* big number functions needed by taipan.c.

	The implementation will actually use the Atari ROM floating point
	routines. To port Taipan to a new cc65 platform, the functions listed
	here will have to be rewritten, but taipan.c itself shouldn't need
	changing (at least, not in relation to bignums!)

	Why call them "bignums" instead of "Float" or something? because
	the whole implementation might get ripped out & replaced with
	64-bit integers, or some other data type. The API shouldn't change
	in that case.

	to declare a bignum:
	bignum(foo);

	...foo actually ends up a pointer (a bignump), which can
	be passed around to the various big_* functions.

   to use the constants:
	bignum(foo) = BIG_0;
	which looks a little weird I admit.
*/

#define bignum(x) char x[6]
#define bignump char *

/****** constants ******/
/* zero */
#define BIG_0 { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }

/* constant initializer for 1.005 goes here */
#define BIG_1_005 { 0x40, 0x01, 0x00, 0x50, 0x00, 0x00 }

/* bignum 100, used for score calculations in final_stats() */
#define BIG_100 { 0x41, 0x01, 0x00, 0x00, 0x00, 0x00 }

/* one million, one hundred million, and one billion */
#define BIG_1M   { 0x43, 0x01, 0x00, 0x00, 0x00, 0x00 }
#define BIG_100M { 0x44, 0x01, 0x00, 0x00, 0x00, 0x00 }
#define BIG_1B   { 0x44, 0x10, 0x00, 0x00, 0x00, 0x00 }

/* max value for a ulong */
#define BIG_MAX_ULONG { 0x44, 0x42, 0x94, 0x96, 0x72, 0x95 }

/****** functions ******/

/* copy dest to src. could be a wrapper for memcpy() */
extern void __fastcall__ big_copy(bignump dest, bignump src);

/* these 2 would be easy to implement, but aren't really needed */
// void int_to_big(int i, bignum *b);
// void uint_to_big(unsigned int i, bignum *b);

/* convert an unsigned long to a bignum */
extern void __fastcall__ ulong_to_big(const unsigned long l, bignump b);

/* convert a bignum to an unsigned long
	returns 0 for success, nonzero for fail (overflow or negative) */
extern char __fastcall__ big_to_ulong(bignump b, unsigned long *l);

/* compare two bignums. like Perl's spaceship operator, <=>
	returns  | if
	---------+----------------
	    0    | a == b
	 positive| a > b
	 negative| a < b

BEWARE: unlike perl's <=>, the return value is *not* guaranteed to
	be 0, 1, or -1. This is more like C's strcmp() or memcmp().
	Do not depend on any particular positive or negative return
	value from this:
	if(big_cmp(a, b) == -1) // WRONG!
	if(big_cmp(a, b) < 0) // Right.  */
extern signed char __fastcall__ big_cmp(bignump a, bignump b);

/* basic math functions. conceptually they return a boolean for
	success, but only division has error checking.
	all can be read as: dest = arg2 OP arg3;
	modulus isn't implemented as taipan doesn't use it for the bank.
	These are __cdecl__ *not* __fastcall__ !!
 */
extern char __cdecl__ big_add(bignump dest, bignump addend1, bignump addend2);
extern char __cdecl__ big_sub(bignump dest, bignump minuend, bignump subtrahend);
extern char __cdecl__ big_mul(bignump dest, bignump multiplicand, bignump multiplier);
extern char __cdecl__ big_div(bignump dest, bignump dividend, bignump divisor);

/* returns true if the bank is maxed out. We do this by checking the exponent
	byte, so the "max" is tied to the bignum implementation, which is why its
	prototype is here rather than bank.h. For Atari floats, it's 1.0e+14, or
	100 trillion.

	If you deposit 1 in the bank at the start of the game and never deposit
	more, the interest will max it out in 1915 (661 turns of play).
 */
extern char __fastcall__ bank_maxed_out(bignump b);

// signed char big_cmp(const bignum *a, const bignum *b)

extern unsigned long cformat_big(char *magnitude, bignump b);
extern void cprintfancy_big(bignump b);