package decimal

import (
	"fmt"
	"math"
	"math/big"
	"math/rand"
	"os"
	"sort"
	"strconv"
	"strings"
	"sync"
	"testing"
)

func TestMain(m *testing.M) {
	sort.Ints(benchPrecs)
	os.Exit(m.Run())
}

var gB *Big

var benchPrecs = []int{
	// Common precisions.
	4, 10, 16, 20, 100,
	// Powers of two.
	32, 64, 128, 256, 512,
	// Exp and Log cutoff.
	299, 300,
	// Large precisions.
	1000, 5000,
}

// assorted values to 1000 precision decimals
// these values came from wolframalpha.com
const (
	_pi_6 = "-.523598775598298873077107230546583814032861566562517636829157432051302734381" +
		"034833104672470890352844663691347752213717774515640768258430371954226568021" +
		"413519575047350450323086850926607437158159155063660738135162610988907688079" +
		"274705631130527545200318190941427820576724768409054441368898934543374856878" +
		"954097834434385931362480253486827138209015285894061315431726668555088424803" +
		"411086897357825323585268238842878394293265325515364352896988768632184186424" +
		"679077063327124927891980958787481871323030501991521638945560406776107181003" +
		"565824399204122865117029976823950461756536196048862792064112469744611567522" +
		"000094687857543926804630961890459631601528939529786911406816870825571691091" +
		"597561841798713281543153923669992685354836993477339069693302271629128551660" +
		"086451201891666666395496341658509955288802682719765837409909224484717107087" +
		"051375557447505876988531361835000522973125481097922201396903436196278191217" +
		"266375581738125911455193260477313725631265625326296976296755361871134435500" +
		"3213127685326515360700332"
	_pi_5 = "-.628318530717958647692528676655900576839433879875021164194988918461563281257" +
		"241799725606965068423413596429617302656461329418768921910116446345071881625" +
		"696223490056820540387704221111928924589790986076392885762195133186689225695" +
		"129646757356633054240381829129713384692069722090865329642678721452049828254" +
		"744917401321263117634976304184192565850818343072873578518072002266106109764" +
		"093304276829390388302321886611454073151918390618437223476386522358621023709" +
		"614892475992549913470377150544978245587636602389825966734672488131328617204" +
		"278989279044947438140435972188740554107843435258635350476934963693533881026" +
		"400113625429052712165557154268551557921834727435744293688180244990686029309" +
		"917074210158455937851784708403991222425804392172806883631962725954954261992" +
		"103741442269999999674595609990211946346563219263719004891891069381660528504" +
		"461650668937007052386237634202000627567750577317506641676284123435533829460" +
		"719650698085751093746231912572776470757518750391556371556106434245361322600" +
		"3855753222391818432840398"
	_pi_4 = "-.785398163397448309615660845819875721049292349843776455243736148076954101571" +
		"552249657008706335529266995537021628320576661773461152387645557931339852032" +
		"120279362571025675484630276389911155737238732595491107202743916483361532118" +
		"912058446695791317800477286412141730865087152613581662053348401815062285318" +
		"431146751651578897043720380230240707313522928841091973147590002832632637205" +
		"116630346036737985377902358264317591439897988273046529345483152948276279637" +
		"018615594990687391837971438181222806984545752987282458418340610164160771505" +
		"348736598806184297675544965235925692634804294073294188096168704616917351283" +
		"000142031786315890206946442835689447402293409294680367110225306238357536637" +
		"396342762698069922314730885504989028032255490216008604539953407443692827490" +
		"129676802837499999593244512487764932933204024079648756114863836727075660630" +
		"577063336171258815482797042752500784459688221646883302095355154294417286825" +
		"899563372607188867182789890715970588446898437989445464445133042806701653250" +
		"4819691527989773041050497"
	_pi_3 = "-1.047197551196597746154214461093167628065723133125035273658314864102605468762" +
		"069666209344941780705689327382695504427435549031281536516860743908453136042" +
		"827039150094700900646173701853214874316318310127321476270325221977815376158" +
		"549411262261055090400636381882855641153449536818108882737797869086749713757" +
		"908195668868771862724960506973654276418030571788122630863453337110176849606" +
		"822173794715650647170536477685756788586530651030728705793977537264368372849" +
		"358154126654249855783961917574963742646061003983043277891120813552214362007" +
		"131648798408245730234059953647900923513072392097725584128224939489223135044" +
		"000189375715087853609261923780919263203057879059573822813633741651143382183" +
		"195123683597426563086307847339985370709673986954678139386604543258257103320" +
		"172902403783333332790992683317019910577605365439531674819818448969434214174" +
		"102751114895011753977062723670001045946250962195844402793806872392556382434" +
		"532751163476251822910386520954627451262531250652593952593510723742268871000" +
		"642625537065303072140066"
	_pi_2 = "-1.570796326794896619231321691639751442098584699687552910487472296153908203143" +
		"104499314017412671058533991074043256641153323546922304775291115862679704064" +
		"240558725142051350969260552779822311474477465190982214405487832966723064237" +
		"824116893391582635600954572824283461730174305227163324106696803630124570636" +
		"862293503303157794087440760460481414627045857682183946295180005665265274410" +
		"233260692073475970755804716528635182879795976546093058690966305896552559274" +
		"037231189981374783675942876362445613969091505974564916836681220328321543010" +
		"697473197612368595351089930471851385269608588146588376192337409233834702566" +
		"000284063572631780413892885671378894804586818589360734220450612476715073274" +
		"792685525396139844629461771009978056064510980432017209079906814887385654980" +
		"259353605674999999186489024975529865866408048159297512229727673454151321261" +
		"154126672342517630965594085505001568919376443293766604190710308588834573651" +
		"799126745214377734365579781431941176893796875978890928890266085613403306500" +
		"963938305597954608210099"
	_2pi_3 = "-2.094395102393195492308428922186335256131446266250070547316629728205210937524" +
		"139332418689883561411378654765391008854871098062563073033721487816906272085" +
		"654078300189401801292347403706429748632636620254642952540650443955630752317" +
		"098822524522110180801272763765711282306899073636217765475595738173499427515" +
		"816391337737543725449921013947308552836061143576245261726906674220353699213" +
		"644347589431301294341072955371513577173061302061457411587955074528736745698" +
		"716308253308499711567923835149927485292122007966086555782241627104428724014" +
		"263297596816491460468119907295801847026144784195451168256449878978446270088" +
		"000378751430175707218523847561838526406115758119147645627267483302286764366" +
		"390247367194853126172615694679970741419347973909356278773209086516514206640" +
		"345804807566666665581985366634039821155210730879063349639636897938868428348" +
		"205502229790023507954125447340002091892501924391688805587613744785112764869" +
		"065502326952503645820773041909254902525062501305187905187021447484537742001" +
		"285251074130606144280133"
	_3pi_4 = "-2.356194490192344928846982537459627163147877049531329365731208444230862304714" +
		"656748971026119006587800986611064884961729985320383457162936673794019556096" +
		"360838087713077026453890829169733467211716197786473321608231749450084596356" +
		"736175340087373953401431859236425192595261457840744986160045205445186855955" +
		"293440254954736691131161140690722121940568786523275919442770008497897911615" +
		"349891038110213956133707074792952774319693964819139588036449458844828838911" +
		"055846784972062175513914314543668420953637258961847375255021830492482314516" +
		"046209796418552893026634895707777077904412882219882564288506113850752053849" +
		"000426095358947670620839328507068342206880227884041101330675918715072609912" +
		"189028288094209766944192656514967084096766470648025813619860222331078482470" +
		"389030408512499998779733537463294798799612072238946268344591510181226981891" +
		"731190008513776446448391128257502353379064664940649906286065462883251860477" +
		"698690117821566601548369672147911765340695313968336393335399128420104959751" +
		"445907458396931912315149"
	_pi = "-3.141592653589793238462643383279502884197169399375105820974944592307816406286" +
		"208998628034825342117067982148086513282306647093844609550582231725359408128" +
		"481117450284102701938521105559644622948954930381964428810975665933446128475" +
		"648233786783165271201909145648566923460348610454326648213393607260249141273" +
		"724587006606315588174881520920962829254091715364367892590360011330530548820" +
		"466521384146951941511609433057270365759591953092186117381932611793105118548" +
		"074462379962749567351885752724891227938183011949129833673362440656643086021" +
		"394946395224737190702179860943702770539217176293176752384674818467669405132" +
		"000568127145263560827785771342757789609173637178721468440901224953430146549" +
		"585371050792279689258923542019956112129021960864034418159813629774771309960" +
		"518707211349999998372978049951059731732816096318595024459455346908302642522" +
		"308253344685035261931188171010003137838752886587533208381420617177669147303" +
		"598253490428755468731159562863882353787593751957781857780532171226806613001" +
		"927876611195909216420199"
	_5pi_4 = "-3.926990816987241548078304229099378605246461749218882276218680740384770507857" +
		"761248285043531677646334977685108141602883308867305761938227789656699260160" +
		"601396812855128377423151381949555778686193662977455536013719582416807660594" +
		"560292233478956589002386432060708654325435763067908310266742009075311426592" +
		"155733758257894485218601901151203536567614644205459865737950014163163186025" +
		"583151730183689926889511791321587957199489941365232646727415764741381398185" +
		"093077974953436959189857190906114034922728764936412292091703050820803857526" +
		"743682994030921488377724826179628463174021470366470940480843523084586756415" +
		"000710158931579451034732214178447237011467046473401835551126531191787683186" +
		"981713813490349611573654427524945140161277451080043022699767037218464137450" +
		"648384014187499997966222562438824664666020120398243780574319183635378303152" +
		"885316680856294077413985213762503922298441108234416510476775771472086434129" +
		"497816863035944335913949453579852942234492189947227322225665214033508266252" +
		"409845763994886520525249"
	_4pi_3 = "-4.188790204786390984616857844372670512262892532500141094633259456410421875048" +
		"278664837379767122822757309530782017709742196125126146067442975633812544171" +
		"308156600378803602584694807412859497265273240509285905081300887911261504634" +
		"197645049044220361602545527531422564613798147272435530951191476346998855031" +
		"632782675475087450899842027894617105672122287152490523453813348440707398427" +
		"288695178862602588682145910743027154346122604122914823175910149057473491397" +
		"432616506616999423135847670299854970584244015932173111564483254208857448028" +
		"526595193632982920936239814591603694052289568390902336512899757956892540176" +
		"000757502860351414437047695123677052812231516238295291254534966604573528732" +
		"780494734389706252345231389359941482838695947818712557546418173033028413280" +
		"691609615133333331163970733268079642310421461758126699279273795877736856696" +
		"411004459580047015908250894680004183785003848783377611175227489570225529738" +
		"131004653905007291641546083818509805050125002610375810374042894969075484002" +
		"570502148261212288560265"
	_3pi_2 = "-4.712388980384689857693965074919254326295754099062658731462416888461724609429" +
		"313497942052238013175601973222129769923459970640766914325873347588039112192" +
		"721676175426154052907781658339466934423432395572946643216463498900169192713" +
		"472350680174747906802863718472850385190522915681489972320090410890373711910" +
		"586880509909473382262322281381444243881137573046551838885540016995795823230" +
		"699782076220427912267414149585905548639387929638279176072898917689657677822" +
		"111693569944124351027828629087336841907274517923694750510043660984964629032" +
		"092419592837105786053269791415554155808825764439765128577012227701504107698" +
		"000852190717895341241678657014136684413760455768082202661351837430145219824" +
		"378056576188419533888385313029934168193532941296051627239720444662156964940" +
		"778060817024999997559467074926589597599224144477892536689183020362453963783" +
		"462380017027552892896782256515004706758129329881299812572130925766503720955" +
		"397380235643133203096739344295823530681390627936672786670798256840209919502" +
		"891814916793863824630298"
	_5pi_3 = "-5.235987755982988730771072305465838140328615665625176368291574320513027343810" +
		"348331046724708903528446636913477522137177745156407682584303719542265680214" +
		"135195750473504503230868509266074371581591550636607381351626109889076880792" +
		"747056311305275452003181909414278205767247684090544413688989345433748568789" +
		"540978344343859313624802534868271382090152858940613154317266685550884248034" +
		"110868973578253235852682388428783942932653255153643528969887686321841864246" +
		"790770633271249278919809587874818713230305019915216389455604067761071810035" +
		"658243992041228651170299768239504617565361960488627920641124697446115675220" +
		"000946878575439268046309618904596316015289395297869114068168708255716910915" +
		"975618417987132815431539236699926853548369934773390696933022716291285516600" +
		"864512018916666663954963416585099552888026827197658374099092244847171070870" +
		"513755574475058769885313618350005229731254810979222013969034361962781912172" +
		"663755817381259114551932604773137256312656253262969762967553618711344355003" +
		"213127685326515360700332"
	_7pi_4 = "-5.497787143782138167309625920739130047345046448906435186706153036538678711000" +
		"865747599060944348704868968759151398244036632414228066713518905519378964224" +
		"841955537997179728392411934729378090160671128168437750419207415383530724832" +
		"384409126870539224603341004884992116055610068295071634373438812705435997229" +
		"018027261561052279306042661611684951194660501887643812033130019828428460435" +
		"816412422257165897645316507850223140079285917911325705418382070637933957459" +
		"130309164934811742865800067268559648891820270910977208928384271149125400537" +
		"441156191643290083728814756651479848443630058513059316673180932318421458981" +
		"000994222504211231448625099849826131816053865062762569771577143668502756461" +
		"774399338886489456203116198534923196225788431512060231779673852105849792430" +
		"907737619862499997152711587414354530532428168557541292804046857089529624414" +
		"039443353198811708379579299267505491217817551528183114667486080060921007781" +
		"296943608250322070279529235011794119128289065926118251115931299646911572753" +
		"373784069592841128735348"
	_2pi = "-6.283185307179586476925286766559005768394338798750211641949889184615632812572" +
		"417997256069650684234135964296173026564613294187689219101164463450718816256" +
		"962234900568205403877042211119289245897909860763928857621951331866892256951" +
		"296467573566330542403818291297133846920697220908653296426787214520498282547" +
		"449174013212631176349763041841925658508183430728735785180720022661061097640" +
		"933042768293903883023218866114540731519183906184372234763865223586210237096" +
		"148924759925499134703771505449782455876366023898259667346724881313286172042" +
		"789892790449474381404359721887405541078434352586353504769349636935338810264" +
		"001136254290527121655571542685515579218347274357442936881802449906860293099" +
		"170742101584559378517847084039912224258043921728068836319627259549542619921" +
		"037414422699999996745956099902119463465632192637190048918910693816605285044" +
		"616506689370070523862376342020006275677505773175066416762841234355338294607" +
		"196506980857510937462319125727764707575187503915563715561064342453613226003" +
		"855753222391818432840398"
)

func neg(str string, n uint) string { return str[:n+2] }
func pos(str string, n uint) string { return str[1 : n+2] }

func equal(x, y *Big) bool {
	if x.Signbit() != y.Signbit() {
		return false
	}
	if x.IsFinite() != y.IsFinite() {
		return false
	}
	if !x.IsFinite() {
		return (x.IsInf(0) && y.IsInf(0)) || (x.IsNaN(0) && y.IsNaN(0))
	}
	if x.Context.Conditions != y.Context.Conditions {
		return false
	}
	cmp := x.Cmp(y) == 0
	scl := x.Scale() == y.Scale()
	prec := x.Precision() == y.Precision()
	return cmp && scl && prec
}

var rnd = rand.New(rand.NewSource(0))

func rndn(min, max int) int {
	return rnd.Intn(max-min) + min
}

func randDec() string {
	b := make([]byte, rndn(5, 50))
	for i := range b {
		b[i] = '0' + byte(rndn(0, 10))
	}
	if rnd.Intn(10) != 0 {
		b[rndn(2, len(b))] = '.'
	}
	if b[0] == '0' {
		if b[1] == '0' && b[2] != '.' {
			b = b[1:]
		}
		b[0] = '-'
	}
	return string(b)
}

var randDecs = func() (a [5000]string) {
	for i := range a {
		a[i] = randDec()
	}
	return a
}()

func TestAcos(t *testing.T) {
	eps := new(Big)
	diff := new(Big)
	for i, tt := range []struct {
		x, r string
	}{
		{"-1.00", "3.141592653589793238462643383279502884197169399375105820974944592307816406286208998628034825342117068"},
		{"-.9999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999", "3.141592653589793238462643383279502884197169399375091678839320861357328389398966901647249128623363299"},
		{"-0.50", "2.094395102393195492308428922186335256131446266250070547316629728205210937524139332418689883561411379"},
		{"0", "1.570796326794896619231321691639751442098584699687552910487472296153908203143104499314017412671058534"},
		{"0.5", "1.047197551196597746154214461093167628065723133125035273658314864102605468762069666209344941780705689"},
		{".9999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999", "1.414213562373095048801688724209698078569671875376948073176679737990732478462107038850387534327641573E-50"},
		{"1.00", "0"},
	} {
		x, _ := new(Big).SetString(tt.x)
		r, _ := new(Big).SetString(tt.r)
		z := new(Big)
		ctx := Context{
			Precision: r.Precision(),
		}
		ctx.Acos(z, x)
		scale := ctx.Precision
		if scale == 0 {
			scale = DefaultPrecision
		}
		eps.SetMantScale(1, scale)
		if z.Cmp(r) != 0 && ctx.Sub(diff, r, z).CmpAbs(eps) > 0 {
			t.Fatalf(`#%d: Acos(%s)
wanted: %s
got   : %s
diff  : %s
`, i, x, r, z, diff)
		}
	}
}

func TestAtan(t *testing.T) {
	const N = 100
	diff := WithPrecision(N)
	eps := New(1, N)
	for i, tt := range []struct {
		x, r string
	}{
		{"+inf", "1.570796326794896619231321691639751442098584699687552910487472296153908203143104499314017412671058534"},
		{"-inf", "-1.570796326794896619231321691639751442098584699687552910487472296153908203143104499314017412671058534"},
		{"0", "0"},
		{".500", "0.4636476090008061162142562314612144020285370542861202638109330887201978641657417053006002839848878926"},
		{"-.500", "-0.4636476090008061162142562314612144020285370542861202638109330887201978641657417053006002839848878926"},
		{".9999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999", "0.7853981633974483096156608458198757210492923498437764552437361480769541015715522496570087063355292669"},
		{"-.9999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999", "-0.7853981633974483096156608458198757210492923498437764552437361480769541015715522496570087063355292669"},
		{"1.00", "0.7853981633974483096156608458198757210492923498437764552437361480769541015715522496570087063355292670"},
		{"-1.00", "-0.7853981633974483096156608458198757210492923498437764552437361480769541015715522496570087063355292670"},
		{".999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999", "0.785398163397448309615660845819875721049292349843776455243736148076954101571552249657008706335529266995537021628320576661773461152387645557931339852032120279362571025675484630276389"},
		{"100.0", "1.560796660108231381024981575430471893537215347143176270859532877957451649939045719334570767484384444"},
		{"0." + strings.Repeat("9", 1000), "0.7853981633974483096156608458198757210492923498437764552437361480769541015715522496570087063355292669955370216283205766617734611523876455579313398520321202793625710256754846302763899111557372387325954911072027439164833615321189120584466957913178004772864121417308650871526135816620533484018150622853184311467516515788970437203802302407073135229288410919731475900028326326372051166303460367379853779023582643175914398979882730465293454831529482762796370186155949906873918379714381812228069845457529872824584183406101641607715053487365988061842976755449652359256926348042940732941880961687046169173512830001420317863158902069464428356894474022934092946803671102253062383575366373963427626980699223147308855049890280322554902160086045399534074436928274901296768028374999995932445124877649329332040240796487561148638367270756606305770633361712588154827970427525007844596882216468833020953551542944172868258995633726071888671827898907159705884468984379894454644451330428067016532504819691527989773041050497"},
		{"100", "1.560796660108231381024981575430471893537215347143176270859532877957451649939045719334570767484384444"},
		{"-100", "-1.560796660108231381024981575430471893537215347143176270859532877957451649939045719334570767484384444"},
	} {
		z := new(Big)
		x, _ := new(Big).SetString(tt.x)
		r, _ := new(Big).SetString(tt.r)
		ctx := Context{
			Precision: N,
		}

		ctx.Atan(z, x)
		if z.Cmp(r) != 0 && ctx.Sub(diff, r, z).CmpAbs(eps) > 0 {
			t.Fatalf(`#%d: Atan(%s)
wanted: %s
got   : %s
diff  : %s
`, i, x, r, z, diff)
		}
	}
}

func TestAsin(t *testing.T) {
	ctx := Context{
		Precision: 100,
	}
	eps := New(1, ctx.Precision)
	var diff Big

	for i, tt := range []struct {
		x, r string
	}{
		{"0", "0"},
		{"1.00", "1.570796326794896619231321691639751442098584699687552910487472296153908203143104499314017412671058534"},
		{"-1.00", "-1.570796326794896619231321691639751442098584699687552910487472296153908203143104499314017412671058534"},
		{"0.5", "0.5235987755982988730771072305465838140328615665625176368291574320513027343810348331046724708903528447"},
		{"-0.50", "-0.5235987755982988730771072305465838140328615665625176368291574320513027343810348331046724708903528447"},
	} {
		var z Big

		x, _ := new(Big).SetString(tt.x)
		r, _ := new(Big).SetString(tt.r)

		ctx.Asin(&z, x)
		if z.Cmp(r) != 0 || ctx.Sub(&diff, r, &z).CmpAbs(eps) > 0 {
			t.Errorf(`#%d: Asin(%s)
wanted: %s
got   : %s
diff  : %s
`, i, x, r, &z, &diff)
		}
	}
}

func TestAtan2(t *testing.T) {
	const N = 1000
	for i, tt := range []struct {
		y, x, r string
	}{
		// Atan2(NaN, NaN) = NaN
		{"NaN", "NaN", "NaN"},

		// Atan2(y, NaN) = NaN
		{"NaN", "NaN", "NaN"},
		{"NaN", "NaN", "NaN"},

		// Atan2(NaN, x) = NaN
		{"NaN", "0", "NaN"},
		{"NaN", "1", "NaN"},

		// Atan2(+/-0, x>=0) = +/-0
		{"0", "0", "0"},
		{"-0", "0", "-0"},
		{"0", "1", "0"},
		{"-0", "1", "-0"},

		// Atan2(+/-0, x<=-0) = +/-pi
		{"0", "-0", pos(_pi, N)},
		{"-0", "-0", neg(_pi, N)},
		{"0", "-1", pos(_pi, N)},
		{"-0", "-1", neg(_pi, N)},

		// Atan2(y>0, 0) = +pi/2
		{"1", "0", pos(_pi_2, N)},

		// Atan2(y<0, 0) = -pi/2
		{"-1", "0", neg(_pi_2, N)},

		// Atan2(+/-Inf, +Inf) = +/-pi/4
		{"+Inf", "+Inf", pos(_pi_4, N)},
		{"-Inf", "+Inf", neg(_pi_4, N)},

		// Atan2(+/-Inf, -Inf) = +/-3pi/4
		{"+Inf", "-Inf", pos(_3pi_4, N)},
		{"-Inf", "-Inf", neg(_3pi_4, N)},

		// Atan2(y, +Inf) = 0
		{"-1", "+Inf", "0"},
		{"0", "+Inf", "0"},
		{"1", "+Inf", "0"},

		// Atan2(y>0, -Inf) = +pi
		{"1", "-Inf", pos(_pi, N)},

		// Atan2(y<0, -Inf) = -pi
		{"-1", "-Inf", neg(_pi, N)},

		// Atan2(+/-Inf, x) = +/-pi/2
		{"+Inf", "-1", pos(_pi_2, N)},
		{"-Inf", "-1", neg(_pi_2, N)},
		{"+Inf", "0", pos(_pi_2, N)},
		{"-Inf", "0", neg(_pi_2, N)},
		{"+Inf", "1", pos(_pi_2, N)},
		{"-Inf", "1", neg(_pi_2, N)},

		// Atan2(y,x>0) = Atan(y/x)
		{"-1", "1", neg(_pi_4, N)},
		{"1", "1", pos(_pi_4, N)},

		// Atan2(y>=0, x<0) = Atan(y/x) + pi
		{"0", "-1", pos(_pi, N)},
		{"1", "-1", pos(_3pi_4, N)},

		// Atan2(y<0, x<0) = Atan(y/x) - pi
		{"-1", "-1", neg(_3pi_4, N)},

		// tests in all the quandrants
		{"1", "1", "0.7853981633974483096156608458198757210492923498437764552437361480769541015715522496570087063355292669955370216283205766617734611523876455579313398520321202793625710256754846302763899111557372387325954911072027439164833615321189120584466957913178004772864121417308650871526135816620533484018150622853184311467516515788970437203802302407073135229288410919731475900028326326372051166303460367379853779023582643175914398979882730465293454831529482762796370186155949906873918379714381812228069845457529872824584183406101641607715053487365988061842976755449652359256926348042940732941880961687046169173512830001420317863158902069464428356894474022934092946803671102253062383575366373963427626980699223147308855049890280322554902160086045399534074436928274901296768028374999995932445124877649329332040240796487561148638367270756606305770633361712588154827970427525007844596882216468833020953551542944172868258995633726071888671827898907159705884468984379894454644451330428067016532504819691527989773041050497"},
		{"-1", "1", "-0.7853981633974483096156608458198757210492923498437764552437361480769541015715522496570087063355292669955370216283205766617734611523876455579313398520321202793625710256754846302763899111557372387325954911072027439164833615321189120584466957913178004772864121417308650871526135816620533484018150622853184311467516515788970437203802302407073135229288410919731475900028326326372051166303460367379853779023582643175914398979882730465293454831529482762796370186155949906873918379714381812228069845457529872824584183406101641607715053487365988061842976755449652359256926348042940732941880961687046169173512830001420317863158902069464428356894474022934092946803671102253062383575366373963427626980699223147308855049890280322554902160086045399534074436928274901296768028374999995932445124877649329332040240796487561148638367270756606305770633361712588154827970427525007844596882216468833020953551542944172868258995633726071888671827898907159705884468984379894454644451330428067016532504819691527989773041050497"},
		{"-1", "-1", "-2.356194490192344928846982537459627163147877049531329365731208444230862304714656748971026119006587800986611064884961729985320383457162936673794019556096360838087713077026453890829169733467211716197786473321608231749450084596356736175340087373953401431859236425192595261457840744986160045205445186855955293440254954736691131161140690722121940568786523275919442770008497897911615349891038110213956133707074792952774319693964819139588036449458844828838911055846784972062175513914314543668420953637258961847375255021830492482314516046209796418552893026634895707777077904412882219882564288506113850752053849000426095358947670620839328507068342206880227884041101330675918715072609912189028288094209766944192656514967084096766470648025813619860222331078482470389030408512499998779733537463294798799612072238946268344591510181226981891731190008513776446448391128257502353379064664940649906286065462883251860477698690117821566601548369672147911765340695313968336393335399128420104959751445907458396931912315149"},
		{"1", "-1", "2.356194490192344928846982537459627163147877049531329365731208444230862304714656748971026119006587800986611064884961729985320383457162936673794019556096360838087713077026453890829169733467211716197786473321608231749450084596356736175340087373953401431859236425192595261457840744986160045205445186855955293440254954736691131161140690722121940568786523275919442770008497897911615349891038110213956133707074792952774319693964819139588036449458844828838911055846784972062175513914314543668420953637258961847375255021830492482314516046209796418552893026634895707777077904412882219882564288506113850752053849000426095358947670620839328507068342206880227884041101330675918715072609912189028288094209766944192656514967084096766470648025813619860222331078482470389030408512499998779733537463294798799612072238946268344591510181226981891731190008513776446448391128257502353379064664940649906286065462883251860477698690117821566601548369672147911765340695313968336393335399128420104959751445907458396931912315149"},

		// bigger values
		{"-2", "1", "-1.107148717794090503017065460178537040070047645401432646676539207433710338977362794013417128686170641434544191005450315810041104123150279960391149134120134938005805785186089159020277066323548671948337093046927250546427929146225306917409377626797415839477802650155236302150617431245551139595028661343071619620451122700330078743309876584050730556855033496160917167182032143557952418577001974141917867556092072396370970780081569293338989816628296388058648735549977420441253262448910061152421541607476658452967630519135912384306883380785499443665836032138897074518792365757298891993783946015848255470901612250351968711897831227460369643896101759549486816806083720841936706092318858507663251672427870156094793691467362050699710474237952805081154791173982305447826322952479276589220603404510278110198878003520641243073406563806386080606837666971733818544308606074699132134849976299998223302991267312103414276992963861911174853919055822470048763842269788306246988883221693259159049588694161190408677435945636"},
		{"2", "1", "1.107148717794090503017065460178537040070047645401432646676539207433710338977362794013417128686170641434544191005450315810041104123150279960391149134120134938005805785186089159020277066323548671948337093046927250546427929146225306917409377626797415839477802650155236302150617431245551139595028661343071619620451122700330078743309876584050730556855033496160917167182032143557952418577001974141917867556092072396370970780081569293338989816628296388058648735549977420441253262448910061152421541607476658452967630519135912384306883380785499443665836032138897074518792365757298891993783946015848255470901612250351968711897831227460369643896101759549486816806083720841936706092318858507663251672427870156094793691467362050699710474237952805081154791173982305447826322952479276589220603404510278110198878003520641243073406563806386080606837666971733818544308606074699132134849976299998223302991267312103414276992963861911174853919055822470048763842269788306246988883221693259159049588694161190408677435945636"},
		{"-100", "1", "-1.560796660108231381024981575430471893537215347143176270859532877957451649939045719334570767484384443574366061972565500368626068848454065791553713241564500301545985135196418856718345713757628924143494438721608047007178718527060232023744938574481833397912364009735237313038166178173143279537136627742826361548235284750352378044025977820371529362683134445031777479652157848191657870077502388383723331123139111702281893170788430751754907735478382271641864205429133785178558795881284854174307762596466668129922037613487147557721948913501048415773028568729401122913139485533613408803919621823252100667169563997472137800355901284244384965079849712693552133035751044605646075445626682013404117070215091999781646367597573057819209803984748055256425128874674285411530539534963728145509712091667740997024765703103732001854246789690581692177245975297965997120707938361216091715901410828242694640618832406496038862320334997082410831649103052659997369163893970982656783920515684968957130015322434411503638848784976"},
		{"100", "1", "1.560796660108231381024981575430471893537215347143176270859532877957451649939045719334570767484384443574366061972565500368626068848454065791553713241564500301545985135196418856718345713757628924143494438721608047007178718527060232023744938574481833397912364009735237313038166178173143279537136627742826361548235284750352378044025977820371529362683134445031777479652157848191657870077502388383723331123139111702281893170788430751754907735478382271641864205429133785178558795881284854174307762596466668129922037613487147557721948913501048415773028568729401122913139485533613408803919621823252100667169563997472137800355901284244384965079849712693552133035751044605646075445626682013404117070215091999781646367597573057819209803984748055256425128874674285411530539534963728145509712091667740997024765703103732001854246789690581692177245975297965997120707938361216091715901410828242694640618832406496038862320334997082410831649103052659997369163893970982656783920515684968957130015322434411503638848784976"},
		{"1", "-100", "3.131592986903128000256303267070223335635800046830729181347005174111359853082150218648588180155442977565440105229206653692172991153229356907416392945628740860271127186547388117271125536069103401608685420936013534840145441591298056140638330157117434352485188293196967487343393341497249976340766752313463223841738587908146465484786438301786156408540816628978072659657823113466068103338194461859694086927855640337464772966764976844813598701784278824201138242660323766553342471824161216619921731687972642694838874294707475879264959610974246028141623919819331594764524755142201555392295814160661334501872129997756201372987681698137270636458744517280370722396485265056258552160699956806089642466354936629243417377575629122330190236001957135163240016260329265670884145209963727331998737067197606863432813862401244231581920243841902953331372647640483628086302023866217660635277854122009298831329140995330612514119461742296788566014682834091938546057690846961547712810781770582360436516286372717101593456995076"},
		{"1", "100", "0.009999666686665238206340116209279548561369352544376639627939418196456553204058779979446645186674090416707981284075652954920853456321225324308966462499740257179156916154550403834434108553845553321696543492797440825788004537177592093148453008153767556660460273726492861267060985150963417266493496827810500745268018407441709396734482661043097683174547738914517700353507417082752363183189685092247424681577416932900986625188115341303783230827514280917409831802056196196224880061591508271306206495039306434994799067733180763821061783972149196595566782360529348938245784074974737784456570514157133167533002002811925772275879129648500706299045091893266456324983175844966401269446592779281408325924752629680124642380483006691770628032461024650389758510980694847823066140036271040979312883862124869383282456193780227873426664460739568976880697044551633844886147143785477203475032465523909550091476182338534789478791748131966902716476728771943807729902904996234144969750400644446176485641503894094315759425123245"},
		{"-1", "100", "-0.009999666686665238206340116209279548561369352544376639627939418196456553204058779979446645186674090416707981284075652954920853456321225324308966462499740257179156916154550403834434108553845553321696543492797440825788004537177592093148453008153767556660460273726492861267060985150963417266493496827810500745268018407441709396734482661043097683174547738914517700353507417082752363183189685092247424681577416932900986625188115341303783230827514280917409831802056196196224880061591508271306206495039306434994799067733180763821061783972149196595566782360529348938245784074974737784456570514157133167533002002811925772275879129648500706299045091893266456324983175844966401269446592779281408325924752629680124642380483006691770628032461024650389758510980694847823066140036271040979312883862124869383282456193780227873426664460739568976880697044551633844886147143785477203475032465523909550091476182338534789478791748131966902716476728771943807729902904996234144969750400644446176485641503894094315759425123245"},
		{"-1", "-100", "-3.131592986903128000256303267070223335635800046830729181347005174111359853082150218648588180155442977565440105229206653692172991153229356907416392945628740860271127186547388117271125536069103401608685420936013534840145441591298056140638330157117434352485188293196967487343393341497249976340766752313463223841738587908146465484786438301786156408540816628978072659657823113466068103338194461859694086927855640337464772966764976844813598701784278824201138242660323766553342471824161216619921731687972642694838874294707475879264959610974246028141623919819331594764524755142201555392295814160661334501872129997756201372987681698137270636458744517280370722396485265056258552160699956806089642466354936629243417377575629122330190236001957135163240016260329265670884145209963727331998737067197606863432813862401244231581920243841902953331372647640483628086302023866217660635277854122009298831329140995330612514119461742296788566014682834091938546057690846961547712810781770582360436516286372717101593456995076"},
		{"-100", "-100", "-2.356194490192344928846982537459627163147877049531329365731208444230862304714656748971026119006587800986611064884961729985320383457162936673794019556096360838087713077026453890829169733467211716197786473321608231749450084596356736175340087373953401431859236425192595261457840744986160045205445186855955293440254954736691131161140690722121940568786523275919442770008497897911615349891038110213956133707074792952774319693964819139588036449458844828838911055846784972062175513914314543668420953637258961847375255021830492482314516046209796418552893026634895707777077904412882219882564288506113850752053849000426095358947670620839328507068342206880227884041101330675918715072609912189028288094209766944192656514967084096766470648025813619860222331078482470389030408512499998779733537463294798799612072238946268344591510181226981891731190008513776446448391128257502353379064664940649906286065462883251860477698690117821566601548369672147911765340695313968336393335399128420104959751445907458396931912315149"},
		{"100", "100", "0.7853981633974483096156608458198757210492923498437764552437361480769541015715522496570087063355292669955370216283205766617734611523876455579313398520321202793625710256754846302763899111557372387325954911072027439164833615321189120584466957913178004772864121417308650871526135816620533484018150622853184311467516515788970437203802302407073135229288410919731475900028326326372051166303460367379853779023582643175914398979882730465293454831529482762796370186155949906873918379714381812228069845457529872824584183406101641607715053487365988061842976755449652359256926348042940732941880961687046169173512830001420317863158902069464428356894474022934092946803671102253062383575366373963427626980699223147308855049890280322554902160086045399534074436928274901296768028374999995932445124877649329332040240796487561148638367270756606305770633361712588154827970427525007844596882216468833020953551542944172868258995633726071888671827898907159705884468984379894454644451330428067016532504819691527989773041050497"},
	} {
		ctx := Context{Precision: N}
		z := new(Big)
		y, _ := new(Big).SetString(tt.y)
		x, _ := new(Big).SetString(tt.x)
		r, _ := new(Big).SetString(tt.r)
		ctx.Atan2(z, y, x)
		if z.Cmp(r) != 0 {
			t.Fatalf(`#%d: Atan2(%s, %s)
wanted: %s
got   : %s
`, i, y, x, r, z)
		}
	}
}

func TestCeil(t *testing.T) {
	for i, s := range []struct {
		x, r string
	}{
		0: {"-2", "-2"},
		1: {"-2.5", "-2"},
		2: {"-2.4", "-2"},
		3: {"5", "5"},
		4: {"0.005", "1"},
		5: {"-0.0005", "-0"},
		6: {"2.9", "3"},
	} {
		x, _ := new(Big).SetString(s.x)
		r, _ := new(Big).SetString(s.r)

		var ctx Context
		z := ctx.Ceil(x, x)
		if z.Cmp(r) != 0 {
			t.Fatalf(`#%d: ceil(%s)
wanted: %s
got   : %s
`, i, s.x, s.r, z)
		}
	}
}

func TestCmp(t *testing.T) {
	for i, test := range []struct {
		x, y string
		r    int
	}{
		{"0", "0", 0},
		{"1", "0", +1},
		{"0", "1", -1},
		{"1", "1", 0},
		{"0.9", "0", +1},
		{"0", "0.9", -1},
		{"0.9", "0.9", 0},
		{"1", "0.9", +1},
		{"0.9", "1", -1},
		{"-0", "0", 0},
		{"-1", "0", -1},
		{"-0", "1", -1},
		{"1", "-1", +1},
		{"-0.9", "0", -1},
		{"0", "-0.9", +1},
		{"-0.9", "-0.9", 0},
		{"-1", "0.9", -1},
		{"0.9", "-1", +1},
	} {
		var x, y Big
		x.SetString(test.x)
		y.SetString(test.y)
		if r := x.Cmp(&y); r != test.r {
			t.Fatalf("#%d: Cmp(%q, %q): expected %d, got %d",
				i, &x, &y, r, test.r)
		}
	}
}

func TestCmpTotal(t *testing.T) {
	for i, test := range []struct {
		x, y string
		r    int
	}{
		{"qnan", "snan", +1},
		{"400", "qnan", -1},
		{"snan", "snan", 0},
		{"snan", "1e+9", +1},
		{"qnan", "1e+12", +1},
		{"-qnan", "12", -1},
		{"12", "qnan", -1},
	} {
		x := new(Big)
		x.Context.OperatingMode = GDA
		x.SetString(test.x)

		y := new(Big)
		y.Context.OperatingMode = GDA
		y.SetString(test.y)

		if r := x.CmpTotal(y); r != test.r {
			t.Fatalf("#%d: CmpTotal(%q, %q): got %d, wanted %d",
				i, x, y, r, test.r)
		}
	}
}

func TestCos(t *testing.T) {
	const N = 100
	diff := WithPrecision(N)
	eps := New(1, 100)
	for i, tt := range []struct {
		x, r string
	}{
		// note the expected values came from wolframalpha.com
		// the input is string values (x)' truncated to specific digit length the result is from those values evaluated @ wolframaplha.com to the same number of digits
		{"0", "1.000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"},
		{pos(_pi_4, N), "0.7071067811865475244008443621048490392848359376884740365883398689953662392310535194251937671638207864"},
		{neg(_pi_4, N), "0.7071067811865475244008443621048490392848359376884740365883398689953662392310535194251937671638207864"},
		{pos(_pi_3, N), "0.5000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003"},
		{neg(_pi_3, N), "0.5000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003"},
		{pos(_pi_2, N), "9.910740432566411533235469223047752911158626797040642405587251420513509692605527798223114744774651910E-100"},
		{neg(_pi_2, N), "9.910740432566411533235469223047752911158626797040642405587251420513509692605527798223114744774651910E-100"},
		{pos(_3pi_4, N), "-0.7071067811865475244008443621048490392848359376884740365883398689953662392310535194251937671638207857"},
		{neg(_3pi_4, N), "-0.7071067811865475244008443621048490392848359376884740365883398689953662392310535194251937671638207857"},
		{pos(_pi, N), "-1.000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"},
		{neg(_pi, N), "-1.000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"},
		{pos(_5pi_4, N), "-0.7071067811865475244008443621048490392848359376884740365883398689953662392310535194251937671638207871"},
		{neg(_5pi_4, N), "-0.7071067811865475244008443621048490392848359376884740365883398689953662392310535194251937671638207871"},
		{pos(_3pi_2, N), "-9.732221297699234599706407669143258733475880391121927216761754261540529077816583394669344234323955729E-100"},
		{neg(_3pi_2, N), "-9.732221297699234599706407669143258733475880391121927216761754261540529077816583394669344234323955729E-100"},
		{pos(_2pi, N), "1.000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"},
		{neg(_2pi, N), "1.000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"},
		{"100.0", "0.8623188722876839341019385139508425355100840085355108292801621126927210880509266241030951056842772851"},
		{"-100.0", "0.8623188722876839341019385139508425355100840085355108292801621126927210880509266241030951056842772851"},
	} {
		ctx := Context{Precision: N}
		z := new(Big)
		x, _ := new(Big).SetString(tt.x)
		r, _ := new(Big).SetString(tt.r)

		ctx.Cos(z, x)
		if z.Cmp(r) != 0 && ctx.Sub(diff, r, z).CmpAbs(eps) > 0 {
			t.Errorf(`#%d: Cos(%s)
wanted: %s
got   : %s
diff  : %s
`, i, x, r, z, diff)
		}
	}
}

func TestExp(t *testing.T) {
	for i, tc := range []struct {
		x    string
		r    string
		prec int
		cond Condition
	}{
		{"0.1", "1.105170918075648", 16, Inexact | Rounded},
		{"0", "1", 16, 0},
		{"0.0000001", "1.000000100000005", 16, Inexact | Rounded},
		{"0.01", "1.010050167084168", 16, Inexact | Rounded},
		{"1", "2.718281828459045", 16, Inexact | Rounded},
		{"2", "7.389056098930650", 16, Inexact | Rounded},
		{"3", "20.08553692318767", 16, Inexact | Rounded},
		{"4", "54.59815003314424", 16, Inexact | Rounded},
		{"8", "2980.95798704172827474359209945288867375596793913283570220896353038773072517336753015737187149001813942468750419097929082503762458828780101423197325987", 150, Inexact | Rounded},
		{"8.5", "4914.76884029913437543137367634782858521479965792103759858028520979760745873316952837106498197949149867029253302796271630670343633985453523115513278361", 150, Inexact | Rounded},
		{"8.5", "4914.768840299134375431373676347828585214799657921037598580285209797607458733169528371064981979491498670292533027962716306703436339854535231155132783610120401650762002683099021054602507219969322181366306285407097420610361642274475387237868040396608369229178064395794276613661196368533479681502003855009", 301, Inexact | Rounded},
		{"-3.2111455189183169875200429E-37", "1.0000000000000000000000000", 26, Inexact | Rounded},
	} {
		var z, x, r Big
		x.SetString(tc.x)
		ctx := Context{Precision: tc.prec}
		ctx.Exp(&z, &x)
		r.Context.Conditions |= tc.cond
		r.SetString(tc.r)
		if !equal(&r, &z) {
			t.Logf("want: %s", &r)
			t.Logf("got : %s", &z)
			t.Fatalf("#%d: expected %q, got %q", i, &r, &z)
		}
	}
}

func TestFloor(t *testing.T) {
	for i, s := range []struct {
		x, r string
	}{
		0: {"-2", "-2"},
		1: {"-2.5", "-3"},
		2: {"-2.4", "-3"},
		3: {"5", "5"},
		4: {"0.005", "0"},
		5: {"-0.0005", "-1"},
		6: {"2.9", "2"},
	} {
		x, _ := new(Big).SetString(s.x)
		r, _ := new(Big).SetString(s.r)

		var ctx Context
		z := ctx.Floor(x, x)
		if z.Cmp(r) != 0 {
			t.Fatalf(`#%d: floor(%s)
wanted: %s
got   : %s
`, i, s.x, s.r, z)
		}
	}
}

func TestBrokenJobs_Exp(t *testing.T) {
	for i, s := range []struct {
		x, r string
	}{
		{
			x: "-4.196711681127197916094391539123262189586909347963506502543424520204269305640664305277347577002702737250370072340050961484385104884969242076870376232111486905959065396493009164151561622858914473431085133053988002190096068967537402110957786645990448175717096753891271854515878515736050199594390165820346179495731423460807010421108300654567720490182E-11",
			r: "0.9999999999580328831896086402857692391751165335212832970499070407439918336957012664619593253323412937604524594000218133755918787968163830746272347910313962376243766200053425149074918367705985619799635171168309589413777382356581724053283138880135649239454288402003937458350598982662476784676965172757399371508486621844945763917842573387863934924333",
		},
	} {
		z := new(Big)
		x, _ := new(Big).SetString(s.x)
		r, _ := new(Big).SetString(s.r)

		ctx := Context{Precision: r.Precision()}
		ctx.Exp(z, x)
		if z.Cmp(r) != 0 {
			t.Fatalf(`#%d: Exp(%s)
wanted: %s
got   : %s
`, i, x, r, z)
		}
	}
}

func TestBig_Float(t *testing.T) {
	for i, test := range randDecs {
		flt, ok := new(big.Float).SetString(test)
		if !ok {
			t.Fatal("!ok")
		}
		fv := new(big.Float).SetPrec(flt.Prec())
		xf := new(Big).SetFloat(flt).Float(fv)
		if xf.String() != flt.String() {
			t.Fatalf("#%d: wanted %s, got %s", i, flt, xf.String())
		}
	}
}

func TestBig_Int(t *testing.T) {
	for i, test := range randDecs {
		a, ok := new(Big).SetString(test)
		if !ok {
			t.Fatalf("#%d: !ok", i)
		}
		iv := test
		switch x := strings.IndexByte(test, '.'); {
		case x > 0:
			iv = test[:x]
		case x == 0:
			iv = "0"
		}
		b, ok := new(big.Int).SetString(iv, 10)
		if !ok {
			t.Fatal("!ok")
		}
		if n := a.Int(nil); n.Cmp(b) != 0 {
			t.Fatalf("#%d: wanted %q, got %q", i, b, n)
		}
	}
}

func TestBig_Int64(t *testing.T) {
	for i, test := range randDecs {
		a, ok := new(Big).SetString(test)
		if !ok {
			t.Fatalf("#%d: !ok", i)
		}
		iv := test
		switch x := strings.IndexByte(test, '.'); {
		case x > 0:
			iv = test[:x]
		case x == 0:
			iv = "0"
		}
		n, ok := a.Int64()
		gv, err := strconv.ParseInt(iv, 10, 64)
		if (err == nil) != ok {
			t.Fatalf("#%d: wanted %t, got %t", i, err == nil, ok)
		}
		if ok && (n != gv) {
			t.Fatalf("#%d: wanted %d, got %d", i, gv, n)
		}
	}
}

func TestBig_Uint64(t *testing.T) {
	for i, test := range randDecs {
		a, ok := new(Big).SetString(test)
		if !ok {
			t.Fatalf("#%d: !ok", i)
		}
		iv := test
		switch x := strings.IndexByte(test, '.'); {
		case x > 0:
			iv = test[:x]
		case x == 0:
			iv = "0"
		}
		n, ok := a.Uint64()
		if _, err := strconv.ParseUint(iv, 10, 64); (err == nil) != ok {
			t.Fatalf("#%d: wanted %t, got %t", i, err == nil, ok)
		}
		if !ok {
			continue
		}
		if ns := strconv.FormatUint(n, 10); ns != iv {
			t.Fatalf("#%d: wanted %q, got %q", i, iv, ns)
		}
	}
}

func TestBig_IsInt(t *testing.T) {
	allZeros := func(s string) bool {
		for _, c := range s {
			if c != '0' {
				return false
			}
		}
		return true
	}
	for i, test := range randDecs {
		x, ok := new(Big).SetString(test)
		if !ok {
			t.Fatal("TestBig_IsInt !ok")
		}
		j := strings.IndexByte(test, '.')
		if got := x.IsInt(); got != (j < 0 || allZeros(test[j+1:])) {
			t.Fatalf("#%d: (%q).IsInt() == %t", i, test, got)
		}
	}
}

// func TestBig_Format(t *testing.T) {
// 	tests := []struct {
// 		format string
// 		a      string
// 		b      string
// 	}{
// 		0: {format: "%e", a: "1.234", b: "1.234"},
// 		1: {format: "%s", a: "1.2134124124", b: "1.2134124124"},
// 		2: {format: "%e", a: "1.00003e-12", b: "1.00003e-12"},
// 		3: {format: "%E", a: "1.000003E-12", b: "1.000003E-12"},
// 	}
// 	for i, v := range tests {
// 		x, ok := new(Big).SetString(v.a)
// 		if !ok {
// 			t.Fatal("invalid SetString")
// 		}
// 		if fs := fmt.Sprintf(v.format, x); fs != v.b {
// 			t.Fatalf("#%d: wanted %q, got %q:", i, v.b, fs)
// 		}
// 	}
// }

func TestLog(t *testing.T) {
	for i, tc := range []struct {
		x    string
		r    string
		prec int
		cond Condition
	}{
		{"0.1", "-2.3025850929940456840179914546843642076011014886287729760333279009675726096773524802359972050895982983419677840422862486334095254650828067566662873690987816894829072083255546808437998948262331985283935053089653777326288461633662222876982198867465436674744042432743651550489343149393914796194044002221051017141748003688084012647080685567743216228355", 347, Inexact | Rounded},
		{"1", "0", 16, 0},
		{"2", "0.6931471805599453", 16, Inexact | Rounded},
		{"3", "1.098612288668110", 16, Inexact | Rounded},
		{"4", "1.386294361119891", 16, Inexact | Rounded},
		{"8", "2.079441541679836", 16, Inexact | Rounded},
		{"8", "2.07944154167983592825169636437452970422650040308076576236204002848018086590908414681758998098925606262600444306171205720105656070727439167109801225491", 150, Inexact | Rounded},
		{"8", "2.07944154167983592825169636437452970422650040308076576236204002848018086590908414681758998098925606262600444306171205720105656070727439167109801225491", 150, Inexact | Rounded},
		{"8.5", "2.140066163496270770832302496414949967512702878225489533176557728388898953831236565306231541041084259976346781026616371557712072606188607807267083814106945309329185637243719043886164643101274986825485156793832316006106028819991510519539804237730079178943061499922793220319663287935533030845458677715534", 301, Inexact | Rounded},
		{"8.5", "2.14006616349627077083230249641494996751270287822548953317655772838889895383123656530623154104108425997634678102661637155771207260618860780726708381411", 150, Inexact | Rounded},
		{"25551879", "17.05622141398427", 16, Inexact | Rounded},
		{"116.366205786997449626683173528449546738506980427865094044860255685353719524083542180490933643924281608471958308160152248251152958937619542134627926841736353", "4.75674216485352034397139416978432263166324396060120679771113301672461844657918372844460852165518840136214128311708110363596888898480309144250926298192", 150, Inexact | Rounded},
		{"7124", "8.87122464440955227020314181246153713151940338752528293971067957068039729012668395735630076216974977271374749345477116795363083886766747473865568206907", 150, Inexact | Rounded},
		{"473106922529980378311.56482325933406", "47.605853088699306834253807095952919421946466382682530244406860766231281144387963081016218293559332098207076292692780155176341801930685553971513707144520845371230925981378594117204387489840434190575911256", 203, Inexact | Rounded},
	} {
		var z, x, r Big
		x.SetString(tc.x)
		r.Context.Conditions |= tc.cond
		r.SetString(tc.r)
		ctx := Context{Precision: tc.prec}
		ctx.Log(&z, &x)
		if !equal(&r, &z) {
			t.Logf("want: %s", &r)
			t.Logf("got : %s", &z)
			t.Fatalf("#%d: expected %q, got %q", i, &r, &z)
		}
	}
}

func TestLog10(t *testing.T) {
	t.Skip("")
	for i, tc := range []struct {
		x    string
		r    string
		prec int
		cond Condition
	}{
		{"2e+25", "3e+1", 1, Inexact | Rounded},
	} {
		var z, x, r Big
		x.SetString(tc.x)
		r.Context.Conditions |= tc.cond
		r.SetString(tc.r)
		ctx := Context{Precision: tc.prec}
		ctx.Log10(&z, &x)
		if !equal(&r, &z) {
			t.Logf("want: %s", &r)
			t.Logf("got : %s", &z)
			t.Fatalf("#%d: expected %q, got %q", i, &r, &z)
		}
	}
}

func TestParallel(t *testing.T) {
	x := New(4, 0)
	y := New(3, 0)
	var wg sync.WaitGroup
	for i := 0; i < 50; i++ {
		wg.Add(1)
		go func() {
			m := new(Big)
			m.Add(x, y)
			m.Mul(m, y)
			m.Quo(m, x)
			m.Sub(m, y)
			m.FMA(m, x, y)
			wg.Done()
		}()
	}
	wg.Wait()
}

func TestPiChudnovskyBrothers(t *testing.T) {
	for i, tt := range []struct {
		input    int
		expected string
	}{
		// note the expected values came from wolframalpha.com
		// the input is string values (x)' truncated to specific digit length the result is from those values evaluated @ wolframaplha.com to the same number of digits
		{5, "3.1416"},
		{16, "3.141592653589793"},
		{100, "3.141592653589793238462643383279502884197169399375105820974944592307816406286208998628034825342117068"},
		{200, "3.1415926535897932384626433832795028841971693993751058209749445923078164062862089986280348253421170679821480865132823066470938446095505822317253594081284811174502841027019385211055596446229489549303820"},
		{500, "3.1415926535897932384626433832795028841971693993751058209749445923078164062862089986280348253421170679821480865132823066470938446095505822317253594081284811174502841027019385211055596446229489549303819644288109756659334461284756482337867831652712019091456485669234603486104543266482133936072602491412737245870066063155881748815209209628292540917153643678925903600113305305488204665213841469519415116094330572703657595919530921861173819326117931051185480744623799627495673518857527248912279381830119491"},
		{1000, "3.141592653589793238462643383279502884197169399375105820974944592307816406286208998628034825342117067982148086513282306647093844609550582231725359408128481117450284102701938521105559644622948954930381964428810975665933446128475648233786783165271201909145648566923460348610454326648213393607260249141273724587006606315588174881520920962829254091715364367892590360011330530548820466521384146951941511609433057270365759591953092186117381932611793105118548074462379962749567351885752724891227938183011949129833673362440656643086021394946395224737190702179860943702770539217176293176752384674818467669405132000568127145263560827785771342757789609173637178721468440901224953430146549585371050792279689258923542019956112129021960864034418159813629774771309960518707211349999998372978049951059731732816096318595024459455346908302642522308253344685035261931188171010003137838752886587533208381420617177669147303598253490428755468731159562863882353787593751957781857780532171226806613001927876611195909216420199"},
		{10000, "3.141592653589793238462643383279502884197169399375105820974944592307816406286208998628034825342117067982148086513282306647093844609550582231725359408128481117450284102701938521105559644622948954930381964428810975665933446128475648233786783165271201909145648566923460348610454326648213393607260249141273724587006606315588174881520920962829254091715364367892590360011330530548820466521384146951941511609433057270365759591953092186117381932611793105118548074462379962749567351885752724891227938183011949129833673362440656643086021394946395224737190702179860943702770539217176293176752384674818467669405132000568127145263560827785771342757789609173637178721468440901224953430146549585371050792279689258923542019956112129021960864034418159813629774771309960518707211349999998372978049951059731732816096318595024459455346908302642522308253344685035261931188171010003137838752886587533208381420617177669147303598253490428755468731159562863882353787593751957781857780532171226806613001927876611195909216420198938095257201065485863278865936153381827968230301952035301852968995773622599413891249721775283479131515574857242454150695950829533116861727855889075098381754637464939319255060400927701671139009848824012858361603563707660104710181942955596198946767837449448255379774726847104047534646208046684259069491293313677028989152104752162056966024058038150193511253382430035587640247496473263914199272604269922796782354781636009341721641219924586315030286182974555706749838505494588586926995690927210797509302955321165344987202755960236480665499119881834797753566369807426542527862551818417574672890977772793800081647060016145249192173217214772350141441973568548161361157352552133475741849468438523323907394143334547762416862518983569485562099219222184272550254256887671790494601653466804988627232791786085784383827967976681454100953883786360950680064225125205117392984896084128488626945604241965285022210661186306744278622039194945047123713786960956364371917287467764657573962413890865832645995813390478027590099465764078951269468398352595709825822620522489407726719478268482601476990902640136394437455305068203496252451749399651431429809190659250937221696461515709858387410597885959772975498930161753928468138268683868942774155991855925245953959431049972524680845987273644695848653836736222626099124608051243884390451244136549762780797715691435997700129616089441694868555848406353422072225828488648158456028506016842739452267467678895252138522549954666727823986456596116354886230577456498035593634568174324112515076069479451096596094025228879710893145669136867228748940560101503308617928680920874760917824938589009714909675985261365549781893129784821682998948722658804857564014270477555132379641451523746234364542858444795265867821051141354735739523113427166102135969536231442952484937187110145765403590279934403742007310578539062198387447808478489683321445713868751943506430218453191048481005370614680674919278191197939952061419663428754440643745123718192179998391015919561814675142691239748940907186494231961567945208095146550225231603881930142093762137855956638937787083039069792077346722182562599661501421503068038447734549202605414665925201497442850732518666002132434088190710486331734649651453905796268561005508106658796998163574736384052571459102897064140110971206280439039759515677157700420337869936007230558763176359421873125147120532928191826186125867321579198414848829164470609575270695722091756711672291098169091528017350671274858322287183520935396572512108357915136988209144421006751033467110314126711136990865851639831501970165151168517143765761835155650884909989859982387345528331635507647918535893226185489632132933089857064204675259070915481416549859461637180270981994309924488957571282890592323326097299712084433573265489382391193259746366730583604142813883032038249037589852437441702913276561809377344403070746921120191302033038019762110110044929321516084244485963766983895228684783123552658213144957685726243344189303968642624341077322697802807318915441101044682325271620105265227211166039666557309254711055785376346682065310989652691862056476931257058635662018558100729360659876486117910453348850346113657686753249441668039626579787718556084552965412665408530614344431858676975145661406800700237877659134401712749470420562230538994561314071127000407854733269939081454664645880797270826683063432858785698305235808933065757406795457163775254202114955761581400250126228594130216471550979259230990796547376125517656751357517829666454779174501129961489030463994713296210734043751895735961458901938971311179042978285647503203198691514028708085990480109412147221317947647772622414254854540332157185306142288137585043063321751829798662237172159160771669254748738986654949450114654062843366393790039769265672146385306736096571209180763832716641627488880078692560290228472104031721186082041900042296617119637792133757511495950156604963186294726547364252308177036751590673502350728354056704038674351362222477158915049530984448933309634087807693259939780541934144737744184263129860809988868741326047215695162396586457302163159819319516735381297416772947867242292465436680098067692823828068996400482435403701416314965897940924323789690706977942236250822168895738379862300159377647165122893578601588161755782973523344604281512627203734314653197777416031990665541876397929334419521541341899485444734567383162499341913181480927777103863877343177207545654532207770921201905166096280490926360197598828161332316663652861932668633606273567630354477628035045077723554710585954870279081435624014517180624643626794561275318134078330336254232783944975382437205835311477119926063813346776879695970309833913077109870408591337464144282277263465947047458784778720192771528073176790770715721344473060570073349243693113835049316312840425121925651798069411352801314701304781643788518529092854520116583934196562134914341595625865865570552690496520985803385072242648293972858478316305777756068887644624824685792603953527734803048029005876075825104747091643961362676044925627420420832085661190625454337213153595845068772460290161876679524061634252257719542916299193064553779914037340432875262888963995879475729174642635745525407909145135711136941091193932519107602082520261879853188770584297259167781314969900901921169717372784768472686084900337702424291651300500516832336435038951702989392233451722013812806965011784408745196012122859937162313017114448464090389064495444006198690754851602632750529834918740786680881833851022833450850486082503930213321971551843063545500766828294930413776552793975175461395398468339363830474611996653858153842056853386218672523340283087112328278921250771262946322956398989893582116745627010218356462201349671518819097303811980049734072396103685406643193950979019069963955245300545058068550195673022921913933918568034490398205955100226353536192041994745538593810234395544959778377902374216172711172364343543947822181852862408514006660443325888569867054315470696574745855033232334210730154594051655379068662733379958511562578432298827372319898757141595781119635833005940873068121602876496286744604774649159950549737425626901049037781986835938146574126804925648798556145372347867330390468838343634655379498641927056387293174872332083760112302991136793862708943879936201629515413371424892830722012690147546684765357616477379467520049075715552781965362132392640616013635815590742202020318727760527721900556148425551879253034351398442532234157623361064250639049750086562710953591946589751413103482276930624743536325691607815478181152843667957061108615331504452127473924544945423682886061340841486377670096120715124914043027253860764823634143346235189757664521641376796903149501910857598442391986291642193994907236234646844117394032659184044378051333894525742399508296591228508555821572503107125701266830240292952522011872676756220415420516184163484756516999811614101002996078386909291603028840026910414079288621507842451670908700069928212066041837180653556725253256753286129104248776182582976515795984703562226293486003415872298053498965022629174878820273420922224533985626476691490556284250391275771028402799806636582548892648802545661017296702664076559042909945681506526530537182941270336931378517860904070866711496558343434769338578171138645587367812301458768712660348913909562009939361031029161615288138437909904231747336394804575931493140529763475748119356709110137751721008031559024853090669203767192203322909433467685142214477379393751703443661991040337511173547191855046449026365512816228824462575916333039107225383742182140883508657391771509682887478265699599574490661758344137522397096834080053559849175417381883999446974867626551658276584835884531427756879002909517028352971634456212964043523117600665101241200659755851276178583829204197484423608007193045761893234922927965019875187212726750798125547095890455635792122103334669749923563025494780249011419521238281530911407907386025152274299581807247162591668545133312394804947079119153267343028244186041426363954800044800267049624820179289647669758318327131425170296923488962766844032326092752496035799646925650493681836090032380929345958897069536534940603402166544375589004563288225054525564056448246515187547119621844396582533754388569094113031509526179378002974120766514793942590298969594699556576121865619673378623625612521632086286922210327488921865436480229678070576561514463204692790682120738837781423356282360896320806822246801224826117718589638140918390367367222088832151375560037279839400415297002878307667094447456013455641725437090697939612257142989467154357846878861444581231459357198492252847160504922124247014121478057345510500801908699603302763478708108175450119307141223390866393833952942578690507643100638351983438934159613185434754649556978103829309716465143840700707360411237359984345225161050702705623526601276484830840761183013052793205427462865403603674532865105706587488225698157936789766974220575059683440869735020141020672358502007245225632651341055924019027421624843914035998953539459094407046912091409387001264560016237428802109276457931065792295524988727584610126483699989225695968815920560010165525637568"},
	} {
		ctx := Context{Precision: tt.input}
		z := new(Big)
		r, _ := new(Big).SetString(tt.expected)

		ctx.piChudnovskyBrothers(z)

		diff := WithPrecision(tt.input)
		eps := New(1, tt.input)

		if z.Cmp(r) != 0 && diff.Sub(r, z).CmpAbs(eps) > 0 {
			t.Errorf(`#%d: piChudnovskyBrothers(%v)
wanted: %s
got   : %s
diff  : %s
`, i, tt.input, r, z, diff)
		}
	}
}

func TestBig_Pow(t *testing.T) {
	for i, tc := range []struct {
		x    string
		y    string
		r    string
		prec int
		cond Condition
	}{
		{"1.08765034381896793182193489290383560918955067691782740351674298471540620999916976181287526081795796075254249040436249111599522293720023611609101965109924448", "2", "1.18298327040951915357496467573374753169315612134813583835650885324453779910318787577367227048434092248354122095707076355820451144387522695510508018997013470", 156, Inexact | Rounded},
	} {
		var x Big
		x.SetString(tc.x)
		var y Big
		y.SetString(tc.y)
		z := WithPrecision(tc.prec)
		ctx := Context{
			MaxScale:      120,
			MinScale:      -36,
			Precision:     156,
			Traps:         0x1b1c,
			Conditions:    0x0,
			RoundingMode:  0x0,
			OperatingMode: 0x0,
		}
		ctx.Pow(z, &x, &y)
		var r Big
		r.Context.Conditions |= tc.cond
		r.SetString(tc.r)
		if !equal(&r, z) {
			t.Logf("want: %s", &r)
			t.Logf("got : %s", z)
			t.Fatalf("#%d: expected %q, got %q", i, &r, z)
		}
	}
}

func TestBig_Prec(t *testing.T) {
	// confirmed to work inside internal/arith/intlen_test.go
}

func TestBig_Round(t *testing.T) {
	for i, test := range []struct {
		v   string
		to  int
		res string
	}{
		{"5.5", 1, "6"},
		{"1.234", 2, "1.2"},
		{"1", 1, "1"},
		{"9.876", 0, "9.876"},
		{"5.65", 2, "5.6"},
		{"5.0002", 2, "5"},
		{"0.000158674", 6, "0.000158674"},
		{"1.58089722856961873690377135139876745465351534188711107066818e+12288", 50, "1.5808972285696187369037713513987674546535153418871e+12288"},
	} {
		bd, _ := new(Big).SetString(test.v)
		r, _ := new(Big).SetString(test.res)
		if bd.Round(test.to).Cmp(r) != 0 {
			t.Fatalf(`#%d:
wanted: %q
got   : %q
`, i, test.res, bd)
		}
	}
}

func TestBig_Scan(t *testing.T) {
	// TODO(eric): this
}

func TestBig_SetFloat64(t *testing.T) {
	if testing.Short() {
		t.Skip("skipping testing all 32-bit floats in short mode")
	}

	const eps = 1e-15
	z := WithPrecision(17)
	for x := uint32(0); x != math.MaxUint32; x++ {
		f := float64(math.Float32frombits(x))
		zf, _ := z.SetFloat64(f).Float64()
		if math.Float64bits(zf) != math.Float64bits(f) {
			if isSpecial(f) || isSpecial(zf) || math.Abs(zf-f) > eps {
				t.Fatalf(`#%d:
wanted: %g
got   : %g
`, x, f, zf)
			}
		}
	}
}

func isSpecial(f float64) bool {
	return math.IsInf(f, 0) || math.IsNaN(f)
}

func TestSin(t *testing.T) {
	const N = 100
	diff := new(Big)
	eps := new(Big)
	for i, tt := range []struct {
		x, r string
	}{
		{"0", "0"},
		{pos(_pi_4, N), "0.7071067811865475244008443621048490392848359376884740365883398689953662392310535194251937671638207863"},
		{neg(_pi_4, N), "-0.7071067811865475244008443621048490392848359376884740365883398689953662392310535194251937671638207863"},
		{pos(_pi_3, N), "0.8660254037844386467637231707529361834714026269051903140279034897259665084544000185405730933786242877"},
		{neg(_pi_3, N), "-0.8660254037844386467637231707529361834714026269051903140279034897259665084544000185405730933786242877"},
		{pos(_pi_2, N), "1.000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"},
		{neg(_pi_2, N), "-1.000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"},
		{pos(_3pi_4, N), "0.7071067811865475244008443621048490392848359376884740365883398689953662392310535194251937671638207871"},
		{neg(_3pi_4, N), "-0.7071067811865475244008443621048490392848359376884740365883398689953662392310535194251937671638207871"},
		{pos(_pi, N), "9.821480865132823066470938446095505822317253594081284811174502841027019385211055596446229489549303820E-N"},
		{neg(_pi, N), "-9.821480865132823066470938446095505822317253594081284811174502841027019385211055596446229489549303820E-N"},
		{pos(_5pi_4, N), "-0.7071067811865475244008443621048490392848359376884740365883398689953662392310535194251937671638207857"},
		{neg(_5pi_4, N), "0.7071067811865475244008443621048490392848359376884740365883398689953662392310535194251937671638207857"},
		{pos(_3pi_2, N), "-1.000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"},
		{neg(_3pi_2, N), "1.000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"},
		{pos(_2pi, N), "-9.642961730265646132941876892191011644634507188162569622349005682054038770422111192892458979098607639E-N"},
		{neg(_2pi, N), "9.642961730265646132941876892191011644634507188162569622349005682054038770422111192892458979098607639E-N"},
		{"7.3303828583761842231", "0.86602540378443864677"},
	} {
		x, _ := new(Big).SetString(tt.x)
		r, _ := new(Big).SetString(tt.r)
		z := new(Big)
		ctx := Context{Precision: r.Precision()}

		ctx.Sin(z, x)
		scale := ctx.Precision
		if scale == 0 {
			scale = DefaultPrecision
		}
		eps.SetMantScale(1, scale)
		if z.Cmp(r) != 0 && ctx.Sub(diff, r, z).CmpAbs(eps) > 0 {
			t.Fatalf(`#%d: Sin(%s)
wanted: %s
got   : %s
diff  : %s
`, i, x, r, z, diff)
		}
	}
}

func TestBig_Format(t *testing.T) {
	x, _ := new(Big).SetString("200.0")
	x.Reduce()

	y := fmt.Sprintf("%.2f", x)

	if y != "200.00" {
		t.Fatalf("want 200.00 but had %s", y)
	}
}

func TestDecimal_Hypot(t *testing.T) {
	ctx := Context{Precision: 100}
	pi := ctx.Pi(new(Big))
	tests := []struct {
		p, q string
		c    int
		a    string
	}{
		{"1", "4", 15, "4.12310562561766"},
		{"1", "4", 10, "4.123105626"},
		{"1", "2", 2, "2.2"},
		{"-12", "599", 5, "599.12"},
		{"1.234", "98.76543", 6, "98.7731"},
		{"3", "4", 1, "5"},
		{pi.String(), pi.String(), 75, "4.4428829381583662470158809900606936986146216893756902230853956069564347931"},
		{"95", "95", 2, "1.3e+2"},
	}
	for i, v := range tests {
		z := new(Big)
		p, _ := new(Big).SetString(v.p)
		q, _ := new(Big).SetString(v.q)
		a, _ := new(Big).SetString(v.a)
		ctx := Context{Precision: a.Precision()}
		if ctx.Hypot(z, p, q).Cmp(a) != 0 {
			t.Fatalf(`#%d:
wanted: %q
got:    %q
`, i, a, z)
		}
	}
}

func TestTan(t *testing.T) {
	diff := new(Big)
	eps := new(Big)

	for i, tt := range []struct {
		x, r string
	}{
		// note the expected values came from wolframalpha.com
		// the first group is|theta|< Pi/2
		{"0", "0"},
		{pos(_pi_4, 100), "0.9999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999998"},
		{neg(_pi_4, 100), "-0.9999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999998"},
		{pos(_pi_3, 100), "1.732050807568877293527446341505872366942805253810380628055806979451933016908800037081146186757248574"},
		{neg(_pi_3, 100), "-1.732050807568877293527446341505872366942805253810380628055806979451933016908800037081146186757248574"},

		// "near" pi/2 .. because at p/2 with infinite precision the result would be Inf
		{"1.4000000000000000000000000", "5.7978837154828896437077202"},
		{"-1.4000000000000000000000000", "-5.7978837154828896437077202"},
		{pos(_pi_2, 17), "5.1998506188720271E16"},
		{neg(_pi_2, 17), "-5.1998506188720271E16"},
		{pos(_pi_2, 30), "1.02548934802693187243286598565E+29"},
		{neg(_pi_2, 30), "-1.02548934802693187243286598565E+29"},
		{pos(_pi_2, 50), "1.8899844771296019351604660349192831433443369043068E49"},
		{neg(_pi_2, 50), "-1.8899844771296019351604660349192831433443369043068E49"},
		{pos(_pi_2, 60), "4.35510876003321014579598280859551726015883372322953933150280E59"},
		{neg(_pi_2, 60), "-4.35510876003321014579598280859551726015883372322953933150280E59"},

		// the next group is   Pi/2 < |theta|
		{pos(_2pi_3, 100), "-1.732050807568877293527446341505872366942805253810380628055806979451933016908800037081146186757248578"},
		{neg(_2pi_3, 100), "1.732050807568877293527446341505872366942805253810380628055806979451933016908800037081146186757248578"},
		{pos(_3pi_4, 100), "-1.000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002"},
		{neg(_3pi_4, 100), "1.000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002"},
		{pos(_pi, 100), "0"},
		{neg(_pi, 100), "0"},
		{pos(_5pi_4, 100), "0.999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999998"},
		{neg(_5pi_4, 100), "-0.999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999998"},
		{pos(_4pi_3, 100), "1.732050807568877293527446341505872366942805253810380628055806979451933016908800037081146186757248574"},
		{neg(_4pi_3, 100), "-1.732050807568877293527446341505872366942805253810380628055806979451933016908800037081146186757248574"},
		{pos(_5pi_3, 100), "-1.732050807568877293527446341505872366942805253810380628055806979451933016908800037081146186757248578"},
		{neg(_5pi_3, 100), "1.732050807568877293527446341505872366942805253810380628055806979451933016908800037081146186757248578"},
		{pos(_7pi_4, 100), "-1.000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002"},
		{neg(_7pi_4, 100), "1.000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002"},
		{pos(_2pi, 100), "0"},
		{neg(_2pi, 100), "0"},
	} {
		x, _ := new(Big).SetString(tt.x)
		r, _ := new(Big).SetString(tt.r)
		z := new(Big)
		ctx := Context{Precision: r.Precision()}

		ctx.Tan(z, x)
		scale := z.Context.Precision
		if scale == 0 {
			scale = DefaultPrecision
		}
		eps.SetMantScale(1, scale)
		if z.Cmp(r) != 0 && ctx.Sub(diff, r, z).CmpAbs(eps) > 0 {
			t.Errorf(`#%d: Tan(%s)
wanted: %s
got   : %s
diff  : %s
`, i, x, r, z, diff)
		}
	}
}

var atan_X, _ = new(Big).SetString("0.7853981633974483096156608458198757210492923498437764552437361480769541015715522496570087063355292670")

func BenchmarkAtan(b *testing.B) {
	for _, prec := range benchPrecs {
		b.Run(fmt.Sprintf("%d", prec), func(b *testing.B) {
			var z Big
			ctx := Context{Precision: prec}
			for j := 0; j < b.N; j++ {
				ctx.Atan(&z, atan_X)
			}
			gB = &z
		})
	}
}

/*
Benchmarks from "Handbook of Continued Fractions for Special Functions."

alg1 - 2.4.1
alg2 - 2.4.4
alg3 - 2.4.7

With a small value for x ("42.2") and a precision of 16, the number of iterations
was:

alg1 - 210
alg2 - 75
alg3 - 150

Code for the algorithm behind the benchmarks:
https://gist.github.com/ericlagergren/cc95be6530aec21e7f91e2204173fd4f

BenchmarkLog_alg1_9-4     	     500	   3209008 ns/op
BenchmarkLog_alg1_19-4    	     300	   5114247 ns/op
BenchmarkLog_alg1_38-4    	     200	  12034146 ns/op
BenchmarkLog_alg1_500-4   	       2	 535323033 ns/op
BenchmarkLog_alg2_9-4     	    3000	    478031 ns/op
BenchmarkLog_alg2_19-4    	    1000	   1954844 ns/op
BenchmarkLog_alg2_38-4    	     300	   4615867 ns/op
BenchmarkLog_alg2_500-4   	       5	 238076617 ns/op
BenchmarkLog_alg3_9-4     	    2000	   1043696 ns/op
BenchmarkLog_alg3_19-4    	     300	   4317666 ns/op
BenchmarkLog_alg3_38-4    	     200	   8040413 ns/op
BenchmarkLog_alg3_500-4   	       2	 550735383 ns/op
*/

var log_X, _ = new(Big).SetString("123456.789")

func BenchmarkLog150(b *testing.B) {
	b.ReportAllocs()
	ctx := Context{Precision: 150}
	var z Big
	for j := 0; j < b.N; j++ {
		gB = ctx.Log(&z, log_X)
	}
	gB = &z
}

func BenchmarkLog(b *testing.B) {
	for _, prec := range benchPrecs {
		b.Run(fmt.Sprintf("%d", prec), func(b *testing.B) {
			b.ReportAllocs()
			var z Big
			ctx := Context{Precision: prec}
			for j := 0; j < b.N; j++ {
				ctx.Log(&z, log_X)
			}
			gB = &z
		})
	}
}

func BenchmarkLn10_CF(b *testing.B) {
	for _, prec := range benchPrecs {
		b.Run(fmt.Sprintf("%d", prec), func(b *testing.B) {
			b.ReportAllocs()
			ctx := Context{Precision: prec}
			var z Big
			for j := 0; j < b.N; j++ {
				ctx.ln10(&z)
			}
			gB = &z
		})
	}
}

func BenchmarkLn10_Taylor(b *testing.B) {
	for _, prec := range benchPrecs {
		b.Run(fmt.Sprintf("%d", prec), func(b *testing.B) {
			b.ReportAllocs()
			ctx := Context{Precision: prec}
			var z Big
			for j := 0; j < b.N; j++ {
				ctx.ln10Taylor(&z)
			}
			gB = &z
		})
	}
}

func BenchmarkSet(b *testing.B) {
	var lB Big
	var ctx Context
	b.ResetTimer()
	for i := 0; i < b.N; i++ {
		ctx.Precision = i % 100
		ctx.Set(&lB, _E.get())
	}
	gB = &lB
}

func BenchmarkScan(b *testing.B) {
	const e = "2.718281828459045235360287471352662497757247093699959574966967627724076630353547594571382178525166427"
	var lB Big
	b.ResetTimer()
	for i := 0; i < b.N; i++ {
		lB.SetString(e[:i%100])
	}
	gB = &lB
}

func BenchmarkPi(b *testing.B) {
	for _, prec := range benchPrecs {
		b.Run(fmt.Sprintf("%d", prec), func(b *testing.B) {
			var z Big
			ctx := Context{Precision: prec}
			for j := 0; j < b.N; j++ {
				ctx.Pi(&z)
			}
			gB = &z
		})
	}
}

func BenchmarkCos(b *testing.B) {
	x := new(Big)
	for i, n := range []string{
		"0", _pi_6, _pi_5, _pi_4, _pi_3, _pi_2, _2pi_3, _pi, _2pi,
	} {
		b.Run(fmt.Sprintf("%d", i), func(b *testing.B) {
			for _, prec := range benchPrecs {
				x.SetString(n)
				b.Run(fmt.Sprintf("%d", prec), func(b *testing.B) {
					ctx := Context{Precision: prec}
					var z Big
					for j := 0; j < b.N; j++ {
						ctx.Cos(&z, x)
					}
					gB = &z
				})
			}
		})
	}
}

var exp_X, _ = new(Big).SetString("123.456")

func BenchmarkExp(b *testing.B) {
	for _, prec := range benchPrecs {
		b.Run(fmt.Sprintf("%d", prec), func(b *testing.B) {
			b.ReportAllocs()
			ctx := Context{Precision: prec}
			var z Big
			for j := 0; j < b.N; j++ {
				ctx.Exp(&z, exp_X)
			}
			gB = &z
		})
	}
}

func BenchmarkPiChudnovskyBrothers(b *testing.B) {
	for _, prec := range benchPrecs {
		b.Run(fmt.Sprintf("%d", prec), func(b *testing.B) {
			var z Big
			ctx := Context{Precision: prec}
			for j := 0; j < b.N; j++ {
				ctx.piChudnovskyBrothers(&z)
			}
			gB = &z
		})
	}
}

func BenchmarkPiContinuedFrac(b *testing.B) {
	piContinuedFrac := func(ctx Context, z *Big) *Big {
		var (
			lasts = new(Big)
			t     = new(Big).SetUint64(3)
			s     = z.SetUint64(3)
			n     = new(Big).SetUint64(1)
			na    = new(Big)
			d     = new(Big)
			da    = new(Big).SetUint64(24)
		)

		for s.Cmp(lasts) != 0 {
			lasts.Copy(s)
			ctx.Add(n, n, na)
			ctx.Add(na, na, eight.get())
			ctx.Add(d, d, da)
			ctx.Add(da, da, thirtyTwo.get())
			ctx.Mul(t, t, n)
			ctx.Quo(t, t, d)
			ctx.Add(s, s, t)
		}
		return ctx.Round(z) // z == s
	}
	for _, prec := range benchPrecs {
		b.Run(fmt.Sprintf("%d", prec), func(b *testing.B) {
			ctx := Context{Precision: prec}
			var z Big
			for j := 0; j < b.N; j++ {
				piContinuedFrac(ctx, &z)
			}
			gB = &z
		})
	}
}

var sin_X, _ = new(Big).SetString("0.7853981633974483096156608458198757210492923498437764552437361480769541015715522496570087063355292670")

func BenchmarkSin(b *testing.B) {
	for _, prec := range benchPrecs {
		b.Run(fmt.Sprintf("%d", prec), func(b *testing.B) {
			ctx := Context{Precision: prec}
			var z Big
			for j := 0; j < b.N; j++ {
				ctx.Sin(&z, sin_X)
			}
			gB = &z
		})
	}
}

var tan_X, _ = new(Big).SetString("0.7853981633974483096156608458198757210492923498437764552437361480769541015715522496570087063355292670")

func BenchmarkTangent(b *testing.B) {
	for _, prec := range benchPrecs {
		b.Run(fmt.Sprintf("%d", prec), func(b *testing.B) {
			var z Big
			ctx := Context{Precision: prec}
			for j := 0; j < b.N; j++ {
				ctx.Tan(&z, tan_X)
			}
			gB = &z
		})
	}
}
