libtom / libtommath

LibTomMath is a free open source portable number theoretic multiple-precision integer library written entirely in C.
https://www.libtom.net
Other
645 stars 194 forks source link

speed please!? #537

Open sjaeckel opened 1 year ago

sjaeckel commented 1 year ago

Creating this issue in order to pull the discussion regarding a mp_isone() macro out of #532

Following up on https://github.com/libtom/libtommath/pull/532#issuecomment-1265290821

[...] It might be tempting to generalize it but since the size of a mp_digit is not fixed over different architectures it would get too complex.

I just thought about it a bit more and had a look into mp_cmp_d() and only then realized that #define mp_isone(a) ( ((a)->used == 1u) && ((a)->dp[0] == 1u) ) would falsely claim -1 as one ...

So I have some follow up questions:

  1. maybe it'd be a better idea to have an inline version of mp_cmp_d()?
    • does the function-call overhead really matter that much? I can imagine that it matters, but have no clue to what extent. Did someone measure this?
    • are there any other candidates that could/should be inlined?
    • how will we do that? We're still providing C89 support, so I guess we can't expect all those compilers being able to handle inline functions correctly.
  2. maybe it's time to think about starting to merge in tfm?
    • Which functions should we start with?
    • Which architectures?
czurnieden commented 1 year ago

I just thought about it a bit more and had a look into mp_cmp_d() and only then realized that #define mp_isone(a) ( ((a)->used == 1u) && ((a)->dp[0] == 1u) ) would falsely claim -1 as one ...

Ah, that's why I have it as is_unity elsewhere (mainly in my JS version). Shouldn't have just renamed it without thinking. My bad, sorry!

#define mp_isunity(a) ( ((a)->used == 1u) && ((a)->dp[0] == 1u) )
#define mp_isone(a) ( (!mp_isneg(a)) && mp_isunity(a) ) 

/* Or together */
#define mp_isone(a)  ( ((a)->sign == MP_ZPOS) && ((a)->used == 1u) && ((a)->dp[0] == 1u) )

/* Generalizing it like this is better done with a full function (mp_cmp_d() in this case) */
#define mp_issmallnumber(a,b)  ( ((a)->sign == MP_ZPOS) && ((a)->used == 1u) && ((a)->dp[0] == b) )

does the function-call overhead really matter that much?

Testing for zero or a small integer happens quite often in loops where a function-overhead would multiply. I am pretty sure that modern compilers would be able to handle it but we also support a lot of the older ones. We don't offer C89 support for nothing. On the other hand: the people who use the older compilers tend to know what they are doing, so...