Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Open
Nicbudd opened this issue Apr 1, 2024 · 6 comments
Labels
performance Performance improvements

Comments

@Nicbudd
Copy link

Nicbudd commented Apr 1, 2024

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.

@printfn
Copy link
Owner

printfn commented Apr 2, 2024

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 printfn added the performance Performance improvements label Apr 2, 2024
@Nicbudd
Copy link
Author

Nicbudd commented Apr 2, 2024

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.

printfn added a commit that referenced this issue May 4, 2024
printfn added a commit that referenced this issue May 4, 2024
@printfn
Copy link
Owner

printfn commented May 4, 2024

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.

@bgkillas
Copy link

bgkillas commented May 4, 2024

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
Copy link

bgkillas commented May 4, 2024

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

@Markos-Th09
Copy link
Contributor

Markos-Th09 commented Sep 16, 2024

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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
performance Performance improvements
Projects
None yet
Development

No branches or pull requests

4 participants