fend icon indicating copy to clipboard operation
fend copied to clipboard

exp(x) or e^x uses large amounts of CPU and stalls on certain fractional values of x

Open Nicbudd opened this issue 2 years ago • 7 comments

Reproduce: > e^(27) - Finishes immediately > e^(27.5) - Finishes immediately > e^(27.2) - Takes ~0.5s > e^(27.02) - Stalls for a very long time, CPU usage jumps to 100% for a single core.

This is what I was trying to calculate when I encountered this error:

> i_c = 1mA
1 mA
> V_BE = 700 mV
700 mV
> V_T = 25.9mV
25.9 mV
> I_S = i_c/(e^(V_BE/V_T))

FWIW, Rust handles this calculation just fine:

fn main() {
        println!("{}", (7000f64/259f64).exp());
}

This program runs in under 2ms on my machine.

Nicbudd avatar Apr 01 '24 19:04 Nicbudd

That's caused by fend's use of arbitrary-precision rational numbers, whereas Rust just uses IEEE floats. You can see more details if you convert the result to a fraction, recurring decimal or use the @debug syntax:

> e^27 to fraction
approx. 71410306039970762789283426758302889490289073593035075381168284413165149457863448019443560038308652663029372407173133034187188198203530227022531144468164243048436419743231672197262698596401880358756231663807677873554780496591618620802013102132422771631202132895592568968622654004708277232900763313847146852329953703338684960782694101353219947446863967226592329017448548867417089293353625274093016683159372434331196180565832672571758355860417492167761609813402330327318284776798663/134217728000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
> e^27.5 to fraction
approx. 113071459683578120472327099102336051648588891081218191369003649549756465261102237007694301508372881808662903082913176552102059568082115284428876870020757975453400867141105099565295953712688575209108205397183707258374426781403808874708210432861342001914095701604030903209919368490400387089900836561769421738856582698458968020002830418041272551242205248340822299743175604579244285544934426857254150309544686793419110800332082802079197543970598348380920361750514942527896031224345516790791027454605093/128900542851112339337197566172636293436602828097556818643071353806407934059695734309972907673747870834094000335784678507293322920070947831195209259568499511900956414314278326484884929480771416380632206420244014065736775812876898350132867352375991098916942676657973164846916206028216383319550901096847223141834174168450619069759725048719635153047876725099735783918863724930189777266272673902695537815472186553026226219478545119405743007493993119787437285413407591711559323225333690952373
> e^27.2 to fraction
approx. 540450167045008595792312004199834380334566558039217527674867169262566023029354549269943291534961887369582253370460426881638164349592917950901274799523416458906691472153703346060457781788609633533139821812387071456979050923486512969399038206775262133433143361773945970688525768622521222728493571352973442796328965489495449459161143584925706880095313563041218468946730192905652506725148068702017021518610385894221154268975585519199351505986414513367725746690430552626085552932492426803039465939/831659873107350606924277819049736548700633569116847123534643389560993233870343316290740405696569335829481700412202030651741112523405216520520258103826026453388012603343813419649546013870839562212187369038410042140117845996513183282593695923409242650749857012844173483349342134770810346513633839847772060655240617712159520702992514401353445472955930171488373469508630213195254916073981130655838797234155989329158534728973598752721979215918401941864343725316964178712306695143072393
> @debug e^27.2
approx. [1, 7656378254019563035, 4822374401389802161, 2864127233296097178, 4741800852526752869, 18012754266386254273, 11136535052342358123, 18411656901359152354, 18173108453789417059, 17246393702594385684, 3885025701834157573, 8808046853525194504, 15725393204157425962, 3666230793870136370, 10071584790018640278, 11747667919465341407, 15447276661555292251, 9714398317530110076, 16360410984259590712, 15423306616511918406, 15258806223664032888, 2910241913288895562, 11797270048586013691, 5586270268566419210, 12759910614835022521, 6885804640814783249, 6597273079670374400]/[40168216, 12140300740075376544, 16821918182857862720, 4274579849032474698, 10718370062722359081, 16624268609432783861, 15081792654813444287, 4733863717375642309, 1401035426730474920, 5531460526609523491, 15800261438749672432, 14580120276478650636, 2481329839418129549, 8256121093525486289, 15600448981039766854, 3476589167266583129, 6260927822833909417, 18074389192336914986, 9829285395187397321, 14304581701864546035, 2365637261319372188, 2234058393639125993, 13854629429954846079, 2148411450467894906, 13395467465607522549, 4941945520756097024] (unitless) (base 10, auto, simplifiable)

As a workaround, you can define your own less precise version of e, for example:

> e = approx. 2.718
> e^27.2
approx. 540871857735.3714207222

Unfortunately if your exponent has a lot of decimal places it will still be extremely slow. Any PRs to improve performance would be more than welcome!

I've also been considering adding a way to opt out of arbitrary-precision maths but this has also not been implemented.

printfn avatar Apr 02 '24 10:04 printfn

I think a way to specify precision would be very helpful. I will see if I can try to figure out a way to make that work, keep in mind I have never contributed to an open source project before.

Nicbudd avatar Apr 02 '24 14:04 Nicbudd

I've now merged in a performance improvement for exponentiation by decimal numbers, so calculations like e^27.2 should be quite a bit faster.

printfn avatar May 04 '24 01:05 printfn

e^27.2 at least now shows 5 more decimals then is accurate also e^0.2*e^27 shows 9 more then is accurate, don't know if you know that

bgkillas avatar May 04 '24 13:05 bgkillas

2^e takes alot of time also, it seems like you turn the number into a fraction but i can't find your fractions code to tell if it is fast or not, also 2^2.536543645276 should probably be computed as (2^(1/250000000000))^634135911319 instead of the big number first then the root. can't tell if that really matters for sure though. but probably is just best to use a taylors series to calculate this, i don't really see the benefit of what your doing

bgkillas avatar May 04 '24 14:05 bgkillas

Fractions are too slow for this kind of computations in general, so for this case arbitrary precision floating point numbers are used if precision is an issue, larger float type such as float-256 or regular old floats

Markos-Th09 avatar Sep 16 '24 14:09 Markos-Th09

The problem is that it creates an instance of fend consuming a lot of CPU. If your program makes a lot of calls to fend, this for example, than your pc starts to lag very fast

TheSketty avatar Jul 16 '25 14:07 TheSketty