mpfr / gmp
Arbitrary Precision Arithmetic: mpir is a fork of gmp (gnu multiple precision), and mpfr is a floatingpoint extension of that.
It has been wrapped/is available for many programs languages, including Ada, C++, Fortran, Haskell, Java, Julia, Lisp, .NET, OCaml, Perl, PHP, Pike, Prolog, Python, R, Racket, Ruby, Rust, Scheme, and now Phix  which means there should be no shortage of examples.
I have seen some performance improvements in my time, but this absolutely has to take the (chocolate covered triplechoc) biscuit.
For demo\rosetta\Ackermann, translating the Go code to calculate ack(3,1e6), which has over 300,000 digits:
Using bigatom.e (as originally submitted by cargoan) took so long that I just had to kill it....
Using bigint.e (wot I wrote meself): 5 minutes to calculate and then 32 minutes to print (gulp).
Using gmp: 0.1s for the lot! (Do I feel humiliated and then some or what?!)
Included in the distribution as builtins\mpfr.e (not an autoinclude), but you have to download the dlls from PCAN or perhaps http://www.atelierweb.com/mpirandmpfr
You should get a readable and straightforward error message when the required dlls cannot be opened.
It is entirely up to you whether to install (simple copy) them to system32/syswow64, builtins, or the application directory.
A future release of phix may offer to download and install them (to builtins) as part of installation, however you would still be responsible for shipping them along with a finished application.
Let me know if any newer prebuilt dlls are uploaded to atelierweb, or elsewhere.
Version: mpfr: 3.1.5, mpir:2.7.2, two dlls, 733K (32 bit, 308K zipped), 936K (64 bit, 373K zipped)
Version 3.1.0p3 was already installed my Ubuntu box, though I also needed to install mpfrdev, in order to compile the recommended version check, which was just the one click via the ubuntu software centre, at least after typing "mpfr" into the search box and picking the one that I needed.
Be warned: mpfr/mpir/gmp are built for speed and are generally very unforgiving, hanging or terminating silently without any clues as to what went wrong  good oldfashioned C for ya!
Making (for example) mpfr_clear() private/internal, and wrapping the C mpfr_init() functions and hence effectively making them nonoptional is the least/best I could do to help.
Use the mpfr_xxx() routines for your ridiculously accurate floats (with ridiculously big exponents).
Use the mpz_xxx() routines for your ridiculously big (and perfectly exact) integers.
Once you understand how to create and display mpfr/mpz variables, the rest is all pretty straightforward.
For comparision, here is the (accurate to ˜15/17dp) behaviour of the standard builtin atom:
(Manually realigned. Aside: 10^60 has seven more digits of accuracy than expected on 32 bit, no idea why, or even how.)
Many operations are performed insitu via procedure calls, eg mpfr_mul(x,y,z) sets x to y*z.
Source and targets may overlay, eg mpfr_mul(x,x,x) etc is perfectly fine and sets x to x*x.
Since phix does not have unsigned integers, if an _ui routine has an _si variant it should be used instead. It also makes sense to utilise the standard integer typechecking within the mpfr.e wrapper, hence some of the _ui routines are syntax coloured illegal/red and linked to their _si counterparts, and where no such exists in C the _ui name is kept, but with fatal errors for args<0.
In the rare case some code actually uses an unsigned value above the normal 30 bit integer limit of 1GB, it must be changed to use xxx_d or xxx_str.
Also take heed of the 1GB..+1GB vs 0..1GB below (obviously not technically accurate for 64bit, but still a necessity for any 32 and 64 bit compatible code).
As ever, this document is just a quick cribsheet: for specific details refer to the mpfr.e source code and/or the official mpfr/mpir/gmp documentation.
Types mpfr and mpz and randstate are optional, you can just use atom if preferred, though when debug_types is true (it is) these also perform some extra anticorruption checks.
More routines (many more) will be added as needed  there are several hundred of them and, at least in my opinion, it is just simply not worthwhile without something that actually uses and therefore tests them.
Note that mpfr_clear() is not publically available, use mpfr_free() instead (which frees both mpfr.dll and mpfr.e allocated memory). Since mpfr_clear() has a different calling convention (to mpfr_free), it is syntax coloured illegal (and linked here). In contrast, mpr_free_str() is invoked internally for you so when translating code you can just delete that statement.
Also note that all mpf_xxx functions have deliberately been expunged in favour of mpfr_ ones.
It has been wrapped/is available for many programs languages, including Ada, C++, Fortran, Haskell, Java, Julia, Lisp, .NET, OCaml, Perl, PHP, Pike, Prolog, Python, R, Racket, Ruby, Rust, Scheme, and now Phix  which means there should be no shortage of examples.
I have seen some performance improvements in my time, but this absolutely has to take the (chocolate covered triplechoc) biscuit.
For demo\rosetta\Ackermann, translating the Go code to calculate ack(3,1e6), which has over 300,000 digits:
Using bigatom.e (as originally submitted by cargoan) took so long that I just had to kill it....
Using bigint.e (wot I wrote meself): 5 minutes to calculate and then 32 minutes to print (gulp).
Using gmp: 0.1s for the lot! (Do I feel humiliated and then some or what?!)
Included in the distribution as builtins\mpfr.e (not an autoinclude), but you have to download the dlls from PCAN or perhaps http://www.atelierweb.com/mpirandmpfr
You should get a readable and straightforward error message when the required dlls cannot be opened.
It is entirely up to you whether to install (simple copy) them to system32/syswow64, builtins, or the application directory.
A future release of phix may offer to download and install them (to builtins) as part of installation, however you would still be responsible for shipping them along with a finished application.
Let me know if any newer prebuilt dlls are uploaded to atelierweb, or elsewhere.
Version: mpfr: 3.1.5, mpir:2.7.2, two dlls, 733K (32 bit, 308K zipped), 936K (64 bit, 373K zipped)
Version 3.1.0p3 was already installed my Ubuntu box, though I also needed to install mpfrdev, in order to compile the recommended version check, which was just the one click via the ubuntu software centre, at least after typing "mpfr" into the search box and picking the one that I needed.
Be warned: mpfr/mpir/gmp are built for speed and are generally very unforgiving, hanging or terminating silently without any clues as to what went wrong  good oldfashioned C for ya!
Making (for example) mpfr_clear() private/internal, and wrapping the C mpfr_init() functions and hence effectively making them nonoptional is the least/best I could do to help.
Use the mpfr_xxx() routines for your ridiculously accurate floats (with ridiculously big exponents).
Use the mpz_xxx() routines for your ridiculously big (and perfectly exact) integers.
Once you understand how to create and display mpfr/mpz variables, the rest is all pretty straightforward.
Example:
include mpfr.e mpz n = mpz_init() for e = 1 to 3 do mpz_ui_pow_ui(n, 10, e*30) mpz_sub_ui(n, n, 1) printf(1, "10^%d1 = %s\n",{e*30,mpz_get_str(n,comma_fill:=true)}) end for n = mpz_clear(n)  output:  10^301 = 999,999,999,999,999,999,999,999,999,999  10^601 = 999,999,999,999,999,999,999,999,999,999,999,999,999,999,999,999,999,999,999,999  10^901 = 999,999,999,999,999,999,999,999,999,999,999,999,999,999,999,999,999,999,999,999,999,999,999,999,999,999,999,999,999,999
for e = 1 to 3 do printf(1, "10^%d1 = %,d\n",{e*30,power(10,e*30)1}) end for  output (32bit):  10^301 = 1,000,000,000,000,000,424,684,240,284,426  10^601 = 1,000,000,000,000,000,000,000,082,442,268,486,026,840,024,008,840,604,006,400,824  10^901 = 999,999,999,999,999,686,426,868,868,000,042,200,008,468,264,024,420,280,668,688,280,420,208,406,626,688,068,446,402,024  output (64bit):  10^301 = 999,999,999,999,999,998,264,846,264,264  10^601 = 999,999,999,999,999,996,186,866,828,000,402,842,426,462,280,408,402,286,040,882  10^901 = 1,000,000,000,000,000,004,244,424,008,082,284,008,804,242,048,002,866,280,462,022,042,286,202,060,886,602,048,286,628,466
Source and targets may overlay, eg mpfr_mul(x,x,x) etc is perfectly fine and sets x to x*x.
Since phix does not have unsigned integers, if an _ui routine has an _si variant it should be used instead. It also makes sense to utilise the standard integer typechecking within the mpfr.e wrapper, hence some of the _ui routines are syntax coloured illegal/red and linked to their _si counterparts, and where no such exists in C the _ui name is kept, but with fatal errors for args<0.
In the rare case some code actually uses an unsigned value above the normal 30 bit integer limit of 1GB, it must be changed to use xxx_d or xxx_str.
Also take heed of the 1GB..+1GB vs 0..1GB below (obviously not technically accurate for 64bit, but still a necessity for any 32 and 64 bit compatible code).
As ever, this document is just a quick cribsheet: for specific details refer to the mpfr.e source code and/or the official mpfr/mpir/gmp documentation.
Types mpfr and mpz and randstate are optional, you can just use atom if preferred, though when debug_types is true (it is) these also perform some extra anticorruption checks.
mpfr (floating point)
string res = 

sequence res = 



integer rounding = 

mpfr res = 

integer precision = 

 
 
mpfr_clear[s]()  use mpfr_free() instead (which clears all memory alocated by mpfr/mpir.dll and mpfr.e).  
object x = 

mpfr_free_str()  invoked automatically within mpfr_get_str() and hence not publically available (there is no need for it to be).  
sequence res = 

string res = 

 
 
 
 
 
mpfr_sqr(mpfr rop, op, integer rounding=default_rounding)  rop := op squared with specified rounding  
mpfr_sin(mpfr rop, op, integer rounding=default_rounding)  rop := sin(op) with specified rounding  
atom res =  mpfr_get_si(mpfr op, integer rounding=default_rounding)  res := op as a machinewordsized signed integer. 
mpz (integer)
mpz res = 

object x = 

 
 
 
 
mpz_mul_2exp(mpz rop, op1, integer op2)  rop := op1 * 2^op2. This operation can also be defined as a left shift by op2 bits.  
mpz_fdiv_q_2exp(mpz q, n, integer bit_count)  bitwise right shift, arithmetic if n ve.  
 
integer res = 

 mpz_tstbit(mpz op, integer bit_index)  Test bit bit_index in op and return 0 or 1 accordingly. 
 mpz_scan0(mpz op, integer starting_bit)  Find first 0 in op >= starting_bit. 
 mpz_scan1(mpz op, integer starting_bit)  Find first 1 in op >= starting_bit. 
 
mpz_ui_pow_ui(mpz rop, integer base, exponent)  rop := base^exponent. The case 0^0 yields 1.  
bool res =  mpz_fits_slong_p(mpz op)  Return nonzero iff the value of op fits in a (signed) long, otherwise, return zero. 
bool res =  mpz_fits_ulong_p(mpz op)  Return nonzero iff the value of op fits in an unsigned long, otherwise, return zero. 
atom res =  mpz_get_si(mpz op)  Return op as an machinewordsized signed integer. Use mpz_fits_slong_p() to find out if the value will fit/be meaningful. 
atom res =  mpz_get_ui(mpz op)  Return op as an machinewordsized unsigned integer. Use mpz_fits_ulong_p() to find out if the value will fit/be meaningful. 
integer res =  mpz_sizeinbase(mpz op, integer base)  Return the size of op measured in number of digits in the given base. 
string res = 

bool res = 

random integers
 gmp_randinit_mt()  Initialize state for a Mersenne Twister algorithm, and invokes gmp_randseed on it (with a NULL mpz_seed). 
 
randstate state =  gmp_randclear(randstate state)  Free all memory occupied by state. Should you forget to invoke this routine, mpfr.e will do so automatically. 
mpz_urandomm(mpz rop, randstate state, mpz n)  Generate a uniform random integer in the range 0 to n1 inclusive, and store it in rop. 
More routines (many more) will be added as needed  there are several hundred of them and, at least in my opinion, it is just simply not worthwhile without something that actually uses and therefore tests them.
Note that mpfr_clear() is not publically available, use mpfr_free() instead (which frees both mpfr.dll and mpfr.e allocated memory). Since mpfr_clear() has a different calling convention (to mpfr_free), it is syntax coloured illegal (and linked here). In contrast, mpr_free_str() is invoked internally for you so when translating code you can just delete that statement.
Also note that all mpf_xxx functions have deliberately been expunged in favour of mpfr_ ones.