Go Down

### Topic: Arbitrary precision (big number) library port for Arduino (Read 71076 times)previous topic - next topic

#### nickgammon ##### Jan 04, 2012, 06:22 amLast Edit: Jan 04, 2012, 11:49 am by Nick Gammon Reason: 1
I love big numbers ... they are so ... big!

So in the spirit of getting your Arduino to handle nice, big, numbers I have ported (with pretty minimal effort on my part) the GNU "bc" library to an Arduino library. This can be downloaded from:

http://www.gammon.com.au/Arduino/BigNumber.zip

Just unzip into your "libraries" folder.

Example sketch:

Code: [Select]
`#include "BigNumber.h"static int DIGITS=0;void print_bignum (bc_num x){  char *s=bc_num2str(x);  Serial.println (s);  free(s);}void setup (){  Serial.begin (115200);  Serial.println ();  Serial.println ();  bc_init_numbers ();  // initialize library  char buf ;  // some big numbers  bc_num a=NULL, b = NULL, c = NULL;  Serial.println ("--- multiply ---");  // test multiplication    bc_str2num(&a, "42",DIGITS);  bc_str2num(&b, "18254546", DIGITS);  bc_multiply(a,b,&c,DIGITS);  // get results as string  print_bignum (c);  bc_free_num (&b);  bc_free_num (&c);  //factorials  Serial.println ("--- factorials ---");  bc_str2num(&b, "1", DIGITS);  for (int i = 2; i <= 100; i++)  {    Serial.print (i);    Serial.print ("! = ");    bc_free_num (&a);    sprintf (buf, "%i", i);    bc_str2num(&a, buf, DIGITS);    bc_multiply(a,b,&b,DIGITS);        print_bignum (b);  }  bc_free_num (&a);  bc_free_num (&b);  Serial.println ("--- power ---");    // test powers    bc_str2num(&a, "2",DIGITS);  for (int i = 1; i <= 300; i++)  {    Serial.print ("2 ^ ");    Serial.print (i);    Serial.print (" = ");    bc_free_num (&b);    sprintf (buf, "%i", i);    bc_str2num(&b, buf, DIGITS);    bc_raise(a,b,&c,DIGITS);        print_bignum (c);    bc_free_num (&c);  }  }  // end of setupvoid loop () { }`

Output from above:

Code: [Select]
`--- multiply ---766690932--- factorials ---2! = 23! = 64! = 245! = 1206! = 7207! = 50408! = 403209! = 36288010! = 362880011! = 3991680012! = 47900160013! = 622702080014! = 8717829120015! = 130767436800016! = 2092278988800017! = 35568742809600018! = 640237370572800019! = 12164510040883200020! = 243290200817664000021! = 5109094217170944000022! = 112400072777760768000023! = 2585201673888497664000024! = 62044840173323943936000025! = 1551121004333098598400000026! = 40329146112660563558400000027! = 1088886945041835216076800000028! = 30488834461171386050150400000029! = 884176199373970195454361600000030! = 26525285981219105863630848000000031! = 822283865417792281772556288000000032! = 26313083693369353016721801216000000033! = 868331761881188649551819440128000000034! = 29523279903960414084761860964352000000035! = 1033314796638614492966665133752320000000036! = 37199332678990121746799944815083520000000037! = 1376375309122634504631597958158090240000000038! = 52302261746660111176000722410007429120000000039! = 2039788208119744335864028173990289735680000000040! = 81591528324789773434561126959611589427200000000041! = 3345252661316380710817006205344075166515200000000042! = 1405006117752879898543142606244511569936384000000000...94! = 10873661566567430802736528525678660100418680358018287230749737443404519986941792763022910921458341545856086565120238534053068800000000000000000000095! = 1032997848823905926259970209939472709539774634011737286921225057123429398759470312487176537538542446856328223686422660735041536000000000000000000000096! = 99167793487094968920957140154189380115818364865126779544437605483849222280909149998768947603700074898207509473896575430563987456000000000000000000000097! = 9619275968248211985332842594956369871234381391917297615810447731933374561248187549880587917558907265126128418967967816764706783232000000000000000000000098! = 942689044888324774562618574305724247380969376407895166349423877729470707002322379888297615920772911982360585058860846042941264756736000000000000000000000099! = 933262154439441526816992388562667004907159682643816214685929638952175999932299156089414639761565182862536979208272237582511852109168640000000000000000000000100! = 93326215443944152681699238856266700490715968264381621468592963895217599993229915608941463976156518286253697920827223758251185210916864000000000000000000000000--- power ---2 ^ 1 = 22 ^ 2 = 42 ^ 3 = 82 ^ 4 = 162 ^ 5 = 322 ^ 6 = 642 ^ 7 = 1282 ^ 8 = 2562 ^ 9 = 5122 ^ 10 = 10242 ^ 11 = 20482 ^ 12 = 40962 ^ 13 = 81922 ^ 14 = 163842 ^ 15 = 327682 ^ 16 = 655362 ^ 17 = 1310722 ^ 18 = 2621442 ^ 19 = 5242882 ^ 20 = 10485762 ^ 21 = 20971522 ^ 22 = 41943042 ^ 23 = 83886082 ^ 24 = 167772162 ^ 25 = 335544322 ^ 26 = 671088642 ^ 27 = 1342177282 ^ 28 = 2684354562 ^ 29 = 5368709122 ^ 30 = 10737418242 ^ 31 = 21474836482 ^ 32 = 42949672962 ^ 33 = 85899345922 ^ 34 = 171798691842 ^ 35 = 343597383682 ^ 36 = 687194767362 ^ 37 = 1374389534722 ^ 38 = 2748779069442 ^ 39 = 5497558138882 ^ 40 = 10995116277762 ^ 41 = 21990232555522 ^ 42 = 43980465111042 ^ 43 = 87960930222082 ^ 44 = 175921860444162 ^ 45 = 351843720888322 ^ 46 = 703687441776642 ^ 47 = 1407374883553282 ^ 48 = 2814749767106562 ^ 49 = 5629499534213122 ^ 50 = 11258999068426242 ^ 51 = 22517998136852482 ^ 52 = 45035996273704962 ^ 53 = 90071992547409922 ^ 54 = 180143985094819842 ^ 55 = 360287970189639682 ^ 56 = 720575940379279362 ^ 57 = 1441151880758558722 ^ 58 = 2882303761517117442 ^ 59 = 5764607523034234882 ^ 60 = 11529215046068469762 ^ 61 = 23058430092136939522 ^ 62 = 46116860184273879042 ^ 63 = 92233720368547758082 ^ 64 = 184467440737095516162 ^ 65 = 368934881474191032322 ^ 66 = 737869762948382064642 ^ 67 = 1475739525896764129282 ^ 68 = 2951479051793528258562 ^ 69 = 5902958103587056517122 ^ 70 = 11805916207174113034242 ^ 71 = 23611832414348226068482 ^ 72 = 47223664828696452136962 ^ 73 = 94447329657392904273922 ^ 74 = 188894659314785808547842 ^ 75 = 377789318629571617095682 ^ 76 = 755578637259143234191362 ^ 77 = 1511157274518286468382722 ^ 78 = 3022314549036572936765442 ^ 79 = 6044629098073145873530882 ^ 80 = 12089258196146291747061762 ^ 81 = 24178516392292583494123522 ^ 82 = 48357032784585166988247042 ^ 83 = 96714065569170333976494082 ^ 84 = 193428131138340667952988162 ^ 85 = 386856262276681335905976322 ^ 86 = 773712524553362671811952642 ^ 87 = 1547425049106725343623905282 ^ 88 = 3094850098213450687247810562 ^ 89 = 6189700196426901374495621122 ^ 90 = 12379400392853802748991242242 ^ 91 = 24758800785707605497982484482 ^ 92 = 49517601571415210995964968962 ^ 93 = 99035203142830421991929937922 ^ 94 = 198070406285660843983859875842 ^ 95 = 396140812571321687967719751682 ^ 96 = 792281625142643375935439503362 ^ 97 = 1584563250285286751870879006722 ^ 98 = 3169126500570573503741758013442 ^ 99 = 6338253001141147007483516026882 ^ 100 = 12676506002282294014967032053762 ^ 101 = 25353012004564588029934064107522 ^ 102 = 50706024009129176059868128215042 ^ 103 = 101412048018258352119736256430082 ^ 104 = 202824096036516704239472512860162 ^ 105 = 405648192073033408478945025720322 ^ 106 = 811296384146066816957890051440642 ^ 107 = 1622592768292133633915780102881282 ^ 108 = 3245185536584267267831560205762562 ^ 109 = 6490371073168534535663120411525122 ^ 110 = 12980742146337069071326240823050242 ^ 111 = 25961484292674138142652481646100482 ^ 112 = 51922968585348276285304963292200962 ^ 113 = 103845937170696552570609926584401922 ^ 114 = 207691874341393105141219853168803842 ^ 115 = 41538374868278621028243970633760768...2 ^ 288 = 4973232364097866421553822481468208401004561507973477174404639768931594970125333755330562 ^ 289 = 9946464728195732843107644962936416802009123015946954348809279537863189940250667510661122 ^ 290 = 19892929456391465686215289925872833604018246031893908697618559075726379880501335021322242 ^ 291 = 39785858912782931372430579851745667208036492063787817395237118151452759761002670042644482 ^ 292 = 79571717825565862744861159703491334416072984127575634790474236302905519522005340085288962 ^ 293 = 159143435651131725489722319406982668832145968255151269580948472605811039044010680170577922 ^ 294 = 318286871302263450979444638813965337664291936510302539161896945211622078088021360341155842 ^ 295 = 636573742604526901958889277627930675328583873020605078323793890423244156176042720682311682 ^ 296 = 1273147485209053803917778555255861350657167746041210156647587780846488312352085441364623362 ^ 297 = 2546294970418107607835557110511722701314335492082420313295175561692976624704170882729246722 ^ 298 = 5092589940836215215671114221023445402628670984164840626590351123385953249408341765458493442 ^ 299 = 10185179881672430431342228442046890805257341968329681253180702246771906498816683530916986882 ^ 300 = 2037035976334486086268445688409378161051468393665936250636140449354381299763336706183397376`

Who would have thought your humble Arduino could calculate 100 factorial! Or 2 to the power 300! It runs pretty fast too. Takes a bit of memory though:

Code: [Select]
`Binary sketch size: 12574 bytes (of a 32256 byte maximum)`

I'm not really an expert on using the library, but hopefully the examples above will give you enough to go on with, to do things like add, subtract, divide etc.

(Output trimmed because of forum posting limits).
Please post technical questions on the forum, not by personal message. Thanks!

#### nickgammon #1
##### Jan 04, 2012, 08:03 amLast Edit: Jan 04, 2012, 12:02 pm by Nick Gammon Reason: 1
Just as another example, you can calculate "e" to around 100 digits like this:

Code: [Select]
`#include "BigNumber.h"static int DIGITS = 103;void print_bignum (bc_num x){  char *s=bc_num2str(x);  Serial.println (s);  free(s);}void setup (){  Serial.begin (115200);  Serial.println ();  Serial.println ();  bc_init_numbers ();  // initialize library  char buf ;  // some big numbers  bc_num n= NULL, e = NULL, one = NULL;  // the number: 1  bc_str2num (&one, "1", DIGITS);  e = bc_copy_num (one);  n = bc_copy_num (one);  for (int j = 1; j <= 200; j++)  {    bc_num E = bc_copy_num (e);    bc_num i = NULL;    sprintf (buf, "%i", j);    bc_str2num(&i, buf, DIGITS);    bc_multiply (i, n, &n, DIGITS);  // n is i! (factorial of i)    bc_free_num (&i);    bc_num inverse = NULL;    bc_divide (one, n, &inverse, DIGITS);    bc_add (inverse, e, &e, DIGITS);    bc_free_num (&inverse);    if (bc_compare (e, E) == 0)  // sequence has converged      break;    bc_free_num (&E);  }  print_bignum (e);} // end of setupvoid loop () { }`

Output:

Code: [Select]
`2.7182818284590452353602874713526624977572470936999595749669676277240766303535475945713821785251664274240`

Time to execute: around 4 seconds.

(edit)

Theory:

http://en.wikipedia.org/wiki/E_%28mathematical_constant%29

E can be calculated as:

Code: [Select]
`1 + (1/1!) + (1/2!) + (1/3!) ...`

That's why the code above is calculating running factorials, and adding the inverse of the factorial to the running total. The code breaks out of the loop when, for the desired number of decimal places, the calculated value doesn't change. That is, at this level of precision, the new amount added does not change the result.
Please post technical questions on the forum, not by personal message. Thanks!

#### Techone #2
##### Jan 04, 2012, 08:38 am
That is impressive.... Really.... !!! and 12K inside the chip... Still impressive...

#### robtillaart #3
##### Jan 04, 2012, 09:48 pm

Well done Nick!

it was somewhere (low) on my todolist and now you did it,

thanks,

Rob Tillaart

Nederlandse sectie - http://arduino.cc/forum/index.php/board,77.0.html -
(Please do not PM for private consultancy)

#### stimmer #4
##### Jan 05, 2012, 12:23 am
I just tried it out on a Mega Code: [Select]
`877! = 1011611483741808350979735614596014894238217322814495678061885986476300120788475589798361596687802128663578042330388633117314918769911893358399855960767087128402653443885249004974897395365479609012783486035483721056839305679987543322025849969875662030830862782926142893333372401656801048774838842075152998418255972797905783699836709546309855893192339084006473628589802797018620887820660848933680457891211257009195751003942681086243147771699300541509917023520768906796204790094872374055294488039306715002830688899997703266103221933805878232123922606100282667038975335043142164163282886560774853187972831209054672730754941302295267776051816732092387029190871291957841784343189241963815856213180566177167112195639046498955376116343921497000536730892516289134843911964047782503358856762108229999177212919928477847641247924465566305875742648991423035640465076829096936501640889769710663169426265396877392790851591894194592057595867010347648202135987859552881929151183698789144026592022450651849397915054771736000737211818458904512736028771559016796149604022595483819743035778947290107102852122610304080676169477575467029871046405065014560927549248111540931483826114271560342485211947257026936230866153767287913951996901524008773010016174894707271992213946054234643582296721076221917553548823648235881143398824484971152482893217762115260242215038066422004691931201792687326732904794242502893084554255994244841293557872138759903613572361115372118957926480182881795156632473733548929885690977865413771097341102912144355671697711537730972632264019256588811705253789509886640902406984090032313082820615025013367001560652771755174854201473950778204978987557794358451512535545900895512531104615368723488464504058808076406951191668900760904086410146183739769732997767263632442026777218726524601613206446515770406124734920046269981962123073162988129456830952669379413202410563973619772261016585559412160000284936236613564082779335945761084993654032138109517877957056794329153855895700267217477802393600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000878! = 888194882725307732160207869615301077141154809431127205338335896126191506052281567842961481891890268966621521166081219877002498679982642368675073533553502498737529723731248626367959913130891096713223900739154707087904910387029063036738696273550831263069497523409153460346700968654671320824308503341984332611228744116561278088456630981660053474222873715757683845901846855782349139506540225363771442028483483654073869381461673993721483743551985875445707146651235100167067805703297944420548560498511295772485344854197983467638628857881561087804804048156048181660220344167878820135362374400360321099040145801550002657602838463415245107373495090777115811629584994338985086653320154444230321755172537103552724507771082826082820230149963074366471249723629301860392954704433953037949076237131025939277592943697203550229015677680767216558902045814469425292328337455947110248440701217805962262756261018458350870367697683102851826569171235085235121475397340687430333794739287536868455347795711672323771369418089584208647271976606918162182233261428816747019352331838834793734385413915720714036304163651846982833676801311260052226778743647082784494388239841932937842799328330429980702016089691669650010700483007678788449853279538079702702794201557552984809163844635618017065256521104922843612015867163151103643904167897804671879980245195137198492664803422318520119515595173979472871490409344917540128238636762946970655743811737831195372716533059296720445059449600570216147523311938055960439636678565833291023465488356862744279750590730127793971127808907284976677212827189680470712313332031048370886716499991961736227370253133601043521988894128783263971551075743446720428006209300986260002309852293739222871834563633491085303146285294868073787868108349323517825572039657469284099510398041888600216395260040846416577517259800625044162744058237103577663097576443715124791716475168838160045172562121163876480250174015746709264680256960378232624428240217260156696846295865420997085476424834616945510501580800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000879! = 780723301915545496568822717391849646807075077489960813492397252694922333819955498133963142582971546421660317104985392271885196339704742642065389635993528696390288627159767542577436763642053274010923808749716987530268416230198546409293314024451180680238088323076645891644750151447456091004567174437604228365270066078457363439753378632879187003841905996151004100547723386232684893626248858094755097543036982131930931186304811440481184210582195584516776581906435653046852601213198893145662184678191428984014618126840027468054354766077892196180422758329166351679333682523565482898983527097916722246056288159562452336032895009342000449381302184793084798422405210023967891168268415756478452822796660114022844842330781804126798982301817542368128228507070156335285407185197444720357238012438171800625004197509841920651304780681394383355274898270918624831956608623777509908379376370451440828962753435224890415053206263447406755554301515639921671776874262464251263405575833744907372250712430559972595033718500744519400952067437481064558183036795929920630010699686335783692524778831918507637911359849973497910801908352597585907338515665785767570567262821059052363820609602447953037072142838977622359405724563749655047421032713972058675756103169089073647255019434708237000360482051227179534961947236409820102991763582170306582502635526525597475052362208217979185054208157927956654040069814182517772721761714630387206398810517553620732617832559121817271207256198901219993672991193551189226440640459367462809626164265682352221900769251782330900621344029503494499270075099729133756123418855291518009423803492934366143858452504435317255828237939200489030993395578489667256217457975566922542030360166196776904342581433838663981465584774189036859536067239055372168677822858915500723469639878820079590211433575904000171637671364749413819052027190414044765862769694025594691918781673408742679706682104503047426139902959841357443653945868172466476872423150971677736527894065705056438133777429628295103730889523200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000880! =     hang :-(  `

It's just gone past 2^2500, no sign of slowing down yet #### stimmer #5
##### Jan 05, 2012, 12:37 am
Spoke to soon, it only got to 3185 Code: [Select]
`2 ^ 3185 = 603303979181690671891548596141956585789608972969291329625935580492657654142441139757170364066959552947782667450916939828176259783186966128205828623840380558541665375425751212793291339618514436915527441751043302586245375146991413065739235395626752064211843140426057093116512399776426682880610088420305574651988940176175181371673722500798917454394947012459530146515294192545906654254786648090019597927750791700133988614242975606045068970733668724398856649169007413989205961386702730110160605454533296520406558279522388202881725831189306904682401198949796424839840482011474812463258957401201742094512685263602083402840867550256088226448960822540403332521865660932039378532052131882547090263437720135438193325591821635195376932171936381715529421837588494653206546993594394796121084530484814595256541114826981366260639046550388335920380460215379497360853931399631163177984487553267754294137957534171524312311742203862276719018953121123406427961849592828764954296322 ^ 3186 =   hang :-( `

It should be able to get a lot further - 877! is around 2^7334 - maybe there's some memory fragmentation issues going on.

#### nickgammon #6
##### Jan 05, 2012, 05:30 am
It wouldn't surprise me a bit about the fragmentation. There are 2208 or so characters in 879!. Assuming that it gradually allocated smaller pieces in the process of getting there, it's a bit of a surprise it got that far. Allocating gradually increasing chunks of memory is a classic way of fragmenting it.

It's a little gratifying it got that far. In any case, I would think the use for it might be in less "tortuous" situations where you just need larger numbers than longs, or more precision than standard floats.
Please post technical questions on the forum, not by personal message. Thanks!

#### Techone #7
##### Jan 05, 2012, 05:52 am
I wonder how far can you go with a PC ( with the latest Pentium Chip ) ? An Assembly ? a C++ ? Java ?  Hum...

Pretty impressive for a 8 bit , 16 Mhz microcontroller...

#### robtillaart #8
##### Jan 05, 2012, 08:06 am
Quote
In any case, I would think the use for it might be in less "tortuous" situations where you just need larger numbers than longs, or more precision than standard floats.

Arduino does support the type long long or  int_64 type - http://www.nongnu.org/avr-libc/user-manual/group__avr__stdint.html -
Rob Tillaart

Nederlandse sectie - http://arduino.cc/forum/index.php/board,77.0.html -
(Please do not PM for private consultancy)

#### nickgammon #9
##### Jan 05, 2012, 10:53 am
Absolutely it does. However it generates a fairly massive amount of code to do arithmetic for the long long type. And long long doesn't have decimal places.
Please post technical questions on the forum, not by personal message. Thanks!

#### nickgammon #10
##### Jan 06, 2012, 11:15 pmLast Edit: Jan 07, 2012, 06:28 am by Nick Gammon Reason: 1
I have updated the BigNumber library to have a C++ wrapper. The updated library is (still) at:

http://www.gammon.com.au/Arduino/BigNumber.zip

The "raw" library was rather fiddly to work with, as it used extensive memory allocations to handle the numbers. This unfortunately is necessary because of the nature of the numbers, you don't know until runtime how large they are going to get.

The C++ class handles allocation and deallocation in the constructor and destructor.

For example, factorials can be produced with more "natural" looking code, like this:

Code: [Select]
`    BigNumber::begin ();  // initialize library  //factorials  BigNumber fact = 1;  for (int i = 2; i <= 200; i++)  {    Serial.print (i);    Serial.print ("! = ");    fact *= i;    printBignum (fact);  }`

The normal arithmetic operations are supported (eg. assignment, add, subtract, divide, multiply, modulus). Also things like a++ or a--.

Also comparisons can be done in natural way.

The only memory allocation you have to worry about is when you get a number to print. Since the library may have to return any size number, it does a malloc to store the number (plus a sign, and decimal point if required). It is up to you to free that string. eg.

Code: [Select]
`// function to display a big number and free it afterwardsvoid printBignum (BigNumber n){  char * s = n.toString ();  Serial.println (s);  free (s);}  // end of printBignum`

An important parameter is the "scale" of the number, which you can set with setScale (n). The scale is effectively the number of decimal places.

For example:

Code: [Select]
`  BigNumber::begin ();  // initialize library  BigNumber a, b = 2, c;  BigNumber::setScale (0);  a = BigNumber (1) / BigNumber (3);  c = b.sqrt ();  Serial.print ("1/3 = ");  printBignum (a);  Serial.print ("sqrt(2) = ");  printBignum (c);`

Output:

Code: [Select]
`1/3 = 0sqrt(2) = 1`

Change the scale to setScale (20) and we get:

Code: [Select]
`1/3 = 0.33333333333333333333sqrt(2) = 1.41421356237309504880`

Change the scale to setScale (100) and we get:

Code: [Select]
`1/3 = 0.3333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333sqrt(2) = 1.4142135623730950488016887242096980785696718753769480731766797379907324784621070388503875343276415727`

So clearly the scale is affecting the results. Note that, of course, the larger the scale the slower the calculation and the more memory it will require.

Some caveats:

• Working with large numbers is necessarily slow - the larger the number, or the more decimal places, the slower.

• Each digit requires a byte of memory, plus some overhead (eg. where the decimal point is) - large numbers will soon gobble up the available memory.

• Doing a toString also requires memory - a byte per digit, plus the sign, decimal point, and trailing 0x00 byte.

• An "error" condition inside the library (eg. running out of memory) calls exit(), effectively sending the library into a tight loop.

• You may need to cast some numbers to avoid "ambiguous" warnings from the compiler.

• If you only have 2048 bytes of RAM, you clearly need to use a library like this with caution. Running out of memory will be quite likely unless you closely manage the size of your numbers, and how many you have.

• Memory fragmentation will quite possibly be a problem, particularly if you calculate numbers of different sizes (eg. factorials).

The supplied library now has some example code (eg. powers, factorials, sine calculations, e^x, and ln(x) ).

Any helpful suggestions welcome, including better algorithms for things like sine, cosine etc.

Note that cosine and tangent can effectively be calculated from the sine.
Please post technical questions on the forum, not by personal message. Thanks!

#### JChristensen #11
##### Jan 07, 2012, 01:36 am
Baha! That is so cool, had to try it just to watch that little bitty machine crunch out those big numbers!

#### JChristensen #12
##### Jan 07, 2012, 02:15 am
I played with the Calculate_E sketch a bit and got 192 decimal places out of an Uno. I checked the result against http://apod.nasa.gov/htmltest/gifcity/e.2mil and it was good. The last two or three places were off, but that is the nature of the computation and is independent of the number of digits calculated. So just a little caveat there before cutting any lumber to length.

Again, super job, Nick!

#### robtillaart #13
##### Jan 07, 2012, 04:29 pm

You could make printing less RAM hungry by implementing another interface to the bignum which fetches max 9 digits at the time as this would fit in a unsigned long. The code below is far from complete (esp fractional part) and not checked but you should get the idea. Greatest advantage is that there is no need to allocate a long string anymore as the number is printed in chunks and there is no free() needed to.

What do you think of it?

Code: [Select]
`void printBignum (BigNumber n){  Serial.print( n.sign );     for (int i=0; i<n.length; i++)  {    Serial.print( n.digit(i) );  }} or // additional wrapper functions with less params can be added// separator can be any char but mostly a "dot comma, space ,...."// chunksize must between 1 and 9, mostly 3 or 5 void printBignumWirhSeparator (BigNumber n, uint8_t chunksize, char separator)  // e.g 12.345.678.901.234.567.890{  Serial.print( n.sign );   int p = n.length  % chunksize;  Serial.print( n.digit(0, p) );  for (int i=p; i<n.length; i+=chunksize)  {    Serial.print(separator);  // default .    Serial.print( n.digit(i) );  }} ==================long digit(int n){  return digit(n, n+1);}long digit(int begin, int end){  long value = 0;    // if (NOT VALID PARAMS) return -1;  // to be elaborated  if (e <= b) e = b+1; // at least one digit  if (e > b+9) e = b+9;  for (int i=b i<e; i++)  {    val = 10*val + (int)nptr[i];  }  return val;}`

Another option is to hand over the address of the print function to be used the BigNum class something like   bignum.do_print( &Serial.print() );
did not elaborate that ..

Rob Tillaart

Nederlandse sectie - http://arduino.cc/forum/index.php/board,77.0.html -
(Please do not PM for private consultancy)

#### nickgammon #14
##### Jan 07, 2012, 11:01 pm
Thanks for the supportive feedback everyone!

Yes you could probably improve on fetching numbers for outputting, although you are possibly trading off saving RAM by losing PROGMEM. It might be an individual choice which you are running out of.

Already it supports getting back a long:

Code: [Select]
`  // for outputting purposes ...  char * toString () const;  // returns number as string, MUST FREE IT after use!  operator long () const;`

So, if you happen to know the number fits into a long you can just access it directly, as in:

Code: [Select]
`BigNumber a = "123456";long foo = a;`

You are right Rob, that simply having a print function that gets called by the main routine (eg. Serial.write) would let the library "output" its stuff without having to allocate memory.
Please post technical questions on the forum, not by personal message. Thanks!