-
Notifications
You must be signed in to change notification settings - Fork 215
Addition of mp_radix_size_overestimate (behaviour like the function in GMP) #343
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
Conversation
|
Oh, using deprectated functions (added test for I don't understand the Windows error but I assume it is for the same reason? |
|
May I propose (again) to kill |
let it rot, disable what doesn't work and add it to the deprecation list, we'll remove it after the next release |
db349d3 to
7498196
Compare
One of the handful of 8-bit MCUs which have enough Flash and RAM to run a stripped down LTM with enough circulation to make it worth the hassle are the bigger versions of ATxmega (and the biggest versions of ATmega to some extent). Will see if I can get my hands on one the next couple of days. No virtual MCUs here, I need the power consumption with the internal clock (datasheet gives only the values with an external clock?), too. And how much work would it be? Oh, that's not much, thought it to be more! Oh, am away tonight, now, actually, (brother-in-law has his 50th and who says no to a free dinner? ;-) ), so till tomorrow. |
sjaeckel
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good!
How about calling this mp_radix_size_approx()? ... or I already thought if it'd probably make sense to have a library-setting to select between the two modes ... but that's probably too much and brings more problems than advantages...
👍
Enjoy & have fun! |
cefe4de to
538d6e3
Compare
or |
|
mp_radix_size_overestimate? |
538d6e3 to
3da2568
Compare
*grmbl* This commit is just the renaming of ( |
ca3db06 to
5743438
Compare
|
@czurnieden the lookup tables look rather large. Could we use smaller tables and a more crude estimate? I think that might be preferable for embedded systems. We will pay more for the allocations then but the constant costs of the tables would be smaller. However allocators are usually rounding themselves so a more crude estimate might not be too bad. |
5743438 to
724db0a
Compare
They are 520 bytes(!) large (260 for 8-bit as long as we have MP_8BIT). But I know where you are coming from and as I am there myself, too, from time to time, I understand.
You can split the tables in halve (e.g.: using a 16-bit type instead of a 32-bit one) but that would loose way too much of the accuracy. Yes, I played with it while designing this function but had a hard time to guarantee the The alternatives, e.g: a fixed-point log, would add a lot of logic which I doubt needs less memory than the tables. So the only thing I can come up with is the functionally stripped down version described above. Which lead me to the question: do we really need all the bases? We got a quick base-10 (didn't take a closer look, but looks quite hardcoded, don't know how much work it would be to extend it) and we can rewrite the old loop to get the power-of-two bases directly. |
|
Ok. 500 bytes are small enough I guess. What's the status? |
|
We could add a configuration option? MP_RADIX_ALL_BASES? Otherwise only enable 10 and power of 2? |
We are only waiting for your OK, so if you are OK with it, drop me a note and I will squash&finish.
So no "squash&finish" here? |
|
@minad just a quick hack as an example. Do you want something like that? |
|
Hmm I am not sure if I like further complications of this function |
Uhm…ooookaaaay? So, can I take that as the answer "No." to my question
? |
|
@sjaeckel @czurnieden What do you think? Is this ready or push this after 1.2 since it is a strict addition? I would love if we could get it out sooner than later since there are already so many changes. After that we can get rid of the deprecated stuff hopefully. 2.0 can then take a while to mature before release, including additions like the this or faster mp_to_radix. Since 1.2 is more like a backward compatibility release I think that would be fine. |
It was ready for 1.2 but isn't anymore with the new branch But the biggest problem ist the reduction of the functionality itself. Not much has been changed up to commit 724db0a that couldn't get squeezed into 1.2 but reducing functionality is a bit much. Either invert the logic ( |
|
MP_RADIX_BASES was just me thinking too loud. As I said, i am not sure if we want that due to the complications it brings. But we can still discuss all that. My point was more to get 1.2 out at some point since I am getting worried with all the changes (API types, deprecations etc etc). 2.0 would give us a bit of a clean slate (think size_t issues, 8bit gone etc). |
sjaeckel
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
looks good IMO after those minor nitpicks
bn_mp_radix_size_overestimate.c
Outdated
| if ((e = mp_init(&bi_k_bis)) != MP_OKAY) { | ||
| /* No "goto" to avoid cluttering this code with even more preprocessor branches */ | ||
| mp_clear_multi(&bi_bit_count, &bi_k, NULL); | ||
| *size = 0; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I just asked myself if 0 is really the good value to return on error... whatever we choose, for sure we should set it once on function-entry and not x-times on each error-case
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I just asked myself if 0 is really the good value to return on error
The returns on error are MP_VALs?
Yes, we could set size to -1 but as we want to change the type of all size-related variables to size_t later we shouldn't introduce things that we know get changed again later.
And also: if the user skips the error-check and use the resulting size for malloc directly and if that value is -1 and it is a 32 bit machine with sizeof(size_t) == 4 and there is enough RAM and and/or space in the swap-partition/file…
set it once on function-entry
Yepp, that's right, will do.
Ahm, now that you mentioned it, would it be a good idea to check if we have something to write on in the first place? I mean if (size == NULL) ...?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
And also: if the user skips the error-check
that was the origin of my thought...
and use the resulting
sizeformallocdirectly and if that value is-1and it is a 32 bit machine withsizeof(size_t) == 4and there is enough RAM and and/or space in the swap-partition/file…
😆
Ahm, now that you mentioned it, would it be a good idea to check if we have something to write on in the first place? I mean
if (size == NULL) ...?
puh, that's nearly nowhere checked... I think yes, we should do it, but maybe we should first discuss it?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
but maybe we should first discuss it?
Hu? Oh, left it in after testing, sorry.
bn_mp_radix_size_overestimate.c
Outdated
|
|
||
| /* And before we forget it: one extra character for the minus sign */ | ||
| if (a->sign == MP_NEG) { | ||
| (*size)++; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Trying to be GMP compatible makes somehow sense, but also I wouldn't care if we'd choose to be sometimes off-by-two or even off-by-X if it would make the implementation a lot easier.
@minad Doesn't this boil down to only a style question here? Or what do you see as an advantage of writing *size += sign ? 1 : 0; over the way it is now?
bn_mp_radix_size_overestimate.c
Outdated
| x >>= 1; | ||
| } | ||
| *size = bit_count/y; | ||
| rem = bit_count - ((*size) * y); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
speaking of "keep in sync" shouldn't base then be called radix or the other way around? :-)
428db2c to
797e05b
Compare
bn_mp_radix_size_overestimate.c
Outdated
| Casting from "long" to "int" can be done because "bi_bit_count" fits into an "int" | ||
| by definition. | ||
| */ | ||
| *size = (int)mp_get_l(&bi_bit_count) + 1 + 1 + (a->sign == MP_NEG); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please just write + 3 here
|
Tried several variations but decide for the simplest one, the "minimalistic version". 100% tested. Excerpt from the logs: |
|
I will take a look. Just one thing - could you please split your PRs.
|
|
Concerning the error table - the error looks indeed quite large. Do you know the error bounds? It would also be helpful if your table would show base, bits, exact size, overestimated size, relative and absolute errors? |
I'd like to see what @czurnieden means by "very large" :-D I just did a simple test of comparing |
Now that you mentioned it: I think those improvements (the power-of-two shortcuts) would be better placed into
But you didn't want it?
Please take a look first, I'm already juggling way too many PRs :-)
Size is in the eye of the beholder ;-) I tarred&feathered the logs and put it into my Google Drive Aaaand forgot to include the actual testing rig, yeah, typical. #include "tommath_private.h"
/*
Table of {0, log_2([1..64])} times 2^p where p is the scale
factor defined in LTM_RADIX_SIZE_SCALE.
*/
/* *INDENT-OFF* */
#define LTM_RADIX_SIZE_SCALE 13
static const uint16_t logbases[65] = {
0u, 0u, 8192u, 12984u, 16384u,
19021u, 21176u, 22997u, 24576u, 25968u,
27213u, 28339u, 29368u, 30314u, 31189u,
32005u, 32768u, 33484u, 34160u, 34799u,
35405u, 35981u, 36531u, 37057u, 37560u,
38042u, 38506u, 38952u, 39381u, 39796u,
40197u, 40584u, 40960u, 41323u, 41676u,
42019u, 42352u, 42675u, 42991u, 43298u,
43597u, 43889u, 44173u, 44451u, 44723u,
44989u, 45249u, 45503u, 45752u, 45995u,
46234u, 46468u, 46698u, 46923u, 47144u,
47360u, 47573u, 47783u, 47988u, 48190u,
48389u, 48584u, 48776u, 48965u, 49152u
};
/* *INDENT-ON* */
static mp_err mp_radix_sizeinbase2(const mp_int *a, const int bits, const int base, int *size)
{
mp_int bi_bit_count, bi_k;
int bit_count;
mp_err err = MP_OKAY;
*size = 0;
if ((base < 2) || (base > 64)) {
return MP_VAL;
}
if (a == NULL) {
bit_count = bits;
} else {
bit_count = mp_count_bits(a) + 1;
}
if (bit_count == 0) {
*size = 2;
return MP_OKAY;
}
if ((err = mp_init_multi(&bi_bit_count, &bi_k, NULL)) != MP_OKAY) {
return err;
}
mp_set_l(&bi_bit_count, bit_count);
mp_set_u32(&bi_k, logbases[base]);
if ((err = mp_mul_2d(&bi_bit_count, LTM_RADIX_SIZE_SCALE, &bi_bit_count)) != MP_OKAY) {
goto LTM_E1;
}
if ((err = mp_div(&bi_bit_count, &bi_k, &bi_bit_count, NULL)) != MP_OKAY) {
goto LTM_E1;
}
*size = (int)mp_get_l(&bi_bit_count) + 3;
#if ( (defined MP_8BIT) && (INT_MAX > 0xFFFF))
*size += 2;
#endif
LTM_E1:
mp_clear_multi(&bi_bit_count, &bi_k, NULL);
return err;
}
#include <stdio.h>
#include <stdlib.h>
#include <limits.h>
#include <math.h>
#ifndef M_LN2
#define M_LN2 0.69314718055994530942
#endif
int main(int argc, char **argv)
{
int integer_size, double_size, base;
double log2_base;
int i;
int is;
int diff_max = 0;
int max_int = INT_MAX;
if (argc < 2) {
printf("usage: %s base\n",argv[0]);
exit(EXIT_FAILURE);
}
base = atoi(argv[1]);
log2_base = log(base)/M_LN2;
#ifdef PRINT_DIFFS
printf("# bits base max diff ds is\n");
#endif
for (i = 1; i < max_int; i++) {
double_size = (int)lrint(ceil((double)i / log2_base));
mp_radix_sizeinbase2(NULL,i,base,&integer_size);
if (integer_size < double_size) {
fprintf(stderr,"FAILURE at i = %d, should be at least %d but is %d\n",i,double_size, integer_size);
exit(EXIT_FAILURE);
}
is = integer_size - double_size;
#ifdef PRINT_DIFFS
if(is > diff_max) {
diff_max = is;
printf("%d %d %d %d %d\n",i,base,diff_max,double_size, integer_size);
}
#endif
#ifdef PRINT_PROGRESS
if (i % 100000000 == 0) {
fprintf(stderr,"%d: ds = %d is = %d\n",i,double_size, integer_size);
}
#endif
}
exit(EXIT_SUCCESS);
}As you can see: I used floating point math to get a value to compare against. That additional error does not influence the result for the max. input of |
4962d00 to
25f7f15
Compare
…pz_sizeinbase in GMP); changed mp_radix_size to use mp_ilogb
25f7f15 to
2bf351b
Compare
I put the the shortcuts for bases that are powers of two in |
|
@czurnieden @sjaeckel I guess it is okay to close this PR in favor of the other ones? From my side I would prefer if we could finish 1.2 now instead of delaying it further. The discussion regarding radix_size_overestimate is not yet concluded, so I would prefer if we move that too to 2.0. Then we can also decide if we add a specialzed to_radix and a specialied radix_size_overestimate only for base 10. Would that be ok? |
OK |
Also changed mp_radix_size to use mp_ilogb while deprecating it at the same time and rewrote mp_fwrite to use mp_radix_sizeinbase instead.
See comment in
bn_mp_fwrite.cfor some of the consequences.