Skip to content

Commit 428983d

Browse files
Merge pull request #2365 from d0sboots/set_str
Make arb_set_str round correctly almost always
2 parents 433ad4f + 9be993e commit 428983d

4 files changed

Lines changed: 140 additions & 8 deletions

File tree

src/acb_hypgeom/test/t-beta_lower.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -188,7 +188,7 @@ TEST_FUNCTION_START(acb_hypgeom_beta_lower, state)
188188
acb_hypgeom_beta_lower(res, a, b, z, 1, prec);
189189
arb_set_str(acb_realref(res2), "0.9999999999999999999999999999999999999999999999999999999999999999998474866919 +/- 2.07e-77", prec);
190190

191-
if (!acb_overlaps(res, res2) || acb_rel_accuracy_bits(res) < acb_rel_accuracy_bits(res2) - 20)
191+
if (!acb_overlaps(res, res2) || acb_rel_accuracy_bits(res) < prec - 20)
192192
{
193193
flint_printf("FAIL: test case (4)\n\n");
194194
flint_printf("res = "); acb_printd(res, 100); flint_printf("\n\n");

src/arb/set_str.c

Lines changed: 21 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -127,26 +127,42 @@ arb_set_float_str(arb_t res, const char * inp, slong prec)
127127
}
128128
else if (fmpz_is_zero(exp))
129129
{
130-
arb_set_round_fmpz(res, man, prec);
130+
int inexact;
131+
inexact = arf_set_round_fmpz(arb_midref(res), man, prec, ARF_RND_NEAR);
132+
133+
/* nearest rounding guarantees half-ulp accuracy */
134+
if (inexact)
135+
arf_mag_set_ulp(arb_radref(res), arb_midref(res), prec+1);
136+
else
137+
mag_zero(arb_radref(res));
131138
}
132139
else
133140
{
141+
slong wp;
134142
arb_t t;
135143
arb_init(t);
136144
arb_set_ui(t, 10);
137145
arb_set_fmpz(res, man);
146+
wp = arb_bits(res);
147+
wp = (wp > prec ? wp : prec) + 10;
138148

139149
if (fmpz_sgn(exp) > 0)
140150
{
141-
arb_pow_fmpz_binexp(t, t, exp, prec + 4);
142-
arb_mul(res, res, t, prec);
151+
arb_pow_fmpz_binexp(t, t, exp, wp);
152+
arb_mul(res, res, t, prec + 10);
143153
}
144154
else
145155
{
146156
fmpz_neg(exp, exp);
147-
arb_pow_fmpz_binexp(t, t, exp, prec + 4);
148-
arb_div(res, res, t, prec);
157+
arb_pow_fmpz_binexp(t, t, exp, wp);
158+
arb_div(res, res, t, prec + 10);
149159
}
160+
/* There doesn't seem to be a faster way to do this in one shot, since
161+
* all arb methods round down. */
162+
arf_set_round(arb_midref(t), arb_midref(res), prec, ARF_RND_NEAR);
163+
arf_swap(arb_midref(t), arb_midref(res));
164+
arf_sub(arb_midref(t), arb_midref(t), arb_midref(res), 30, ARF_RND_UP);
165+
arb_add_error_arf(res, arb_midref(t));
150166

151167
arb_clear(t);
152168
}

src/arb/test/t-set_str.c

Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,56 @@ const char * testdata_floats[] = {
100100
"-12345.125",
101101
"+12345.125",
102102

103+
"1.0625",
104+
"1.03125",
105+
"1.015625",
106+
"1.0078125",
107+
"1.00390625",
108+
"1.001953125",
109+
"1.0009765625",
110+
"1.00048828125",
111+
"1.000244140625",
112+
"1.0001220703125",
113+
"1.00006103515625",
114+
"1.000030517578125",
115+
"1.0000152587890625",
116+
"1.00000762939453125",
117+
"1.000003814697265625",
118+
"1.0000019073486328125",
119+
"1.00000095367431640625",
120+
"1.000000476837158203125",
121+
"1.0000002384185791015625",
122+
"1.00000011920928955078125",
123+
"1.000000059604644775390625",
124+
"1.0000000298023223876953125",
125+
"1.00000001490116119384765625",
126+
"1.000000007450580596923828125",
127+
"1.0000000037252902984619140625",
128+
"1.00000000186264514923095703125",
129+
"1.000000000931322574615478515625",
130+
"1.0000000004656612873077392578125",
131+
"1.00000000023283064365386962890625",
132+
"1.000000000116415321826934814453125",
133+
"1.0000000000582076609134674072265625",
134+
"1.00000000002910383045673370361328125",
135+
"1.000000000014551915228366851806640625",
136+
"1.0000000000072759576141834259033203125",
137+
"1.00000000000363797880709171295166015625",
138+
"1.000000000001818989403545856475830078125",
139+
"1.0000000000009094947017729282379150390625",
140+
"1.00000000000045474735088646411895751953125",
141+
"1.000000000000227373675443232059478759765625",
142+
"1.0000000000001136868377216160297393798828125",
143+
"1.00000000000005684341886080801486968994140625",
144+
"1.000000000000028421709430404007434844970703125",
145+
"1.0000000000000142108547152020037174224853515625",
146+
"1.00000000000000710542735760100185871124267578125",
147+
"1.000000000000003552713678800500929355621337890625",
148+
"1.0000000000000017763568394002504646778106689453125",
149+
"1.00000000000000088817841970012523233890533447265625",
150+
"1.000000000000000444089209850062616169452667236328125",
151+
"1.0000000000000002220446049250313080847263336181640625",
152+
103153
"inf",
104154
"-inf",
105155
"+inf",
@@ -149,6 +199,31 @@ const char * testdata_invalid[] = {
149199
NULL,
150200
};
151201

202+
const char * testdata_rounding[] = {
203+
"1.1",
204+
"-1.1",
205+
"1.01",
206+
"1.001",
207+
"1.0001",
208+
"1.00001",
209+
"1.000001",
210+
"1.0000001",
211+
"1.00000001",
212+
"1.000000001",
213+
"1.0000000001",
214+
"1.00000000001",
215+
"1.000000000001",
216+
"1.0000000000001",
217+
"1.00000000000001",
218+
"1.000000000000001",
219+
"1.0000000000000001",
220+
"1.00000000000000001",
221+
"100000000000000001",
222+
"1000000000000000001",
223+
"10000000000000000001",
224+
NULL,
225+
};
226+
152227
TEST_FUNCTION_START(arb_set_str, state)
153228
{
154229
arb_t t, u, v;
@@ -291,6 +366,47 @@ TEST_FUNCTION_START(arb_set_str, state)
291366
}
292367
}
293368

369+
for (i = 0; testdata_rounding[i] != NULL; i++)
370+
{
371+
arb_const_pi(t, 53);
372+
373+
error = arb_set_str(t, testdata_rounding[i], 53);
374+
375+
/* It is not *guaranteed* that the rounding will be to half-ulp
376+
* accuracy, just like it is not guaranteed that all inputs will be
377+
* correctly rounded. But it is very likely for a random string, and
378+
* it *is* guaranteed if the input is the result of get_str performed
379+
* with a sufficient number of digits.
380+
* Thus, we are justified in testing for these things here. */
381+
x = strtod(testdata_rounding[i], NULL);
382+
arf_set_d(arb_midref(u), x);
383+
arf_mag_set_ulp(arb_radref(u), arb_midref(u), 54);
384+
385+
if (error != 0 || !arf_equal(arb_midref(t), arb_midref(u)) ||
386+
mag_cmp(arb_radref(t), arb_radref(u)) > 0)
387+
{
388+
flint_printf("FAIL (valid input): %s\n", testdata_rounding[i]);
389+
arb_printd(t, 19); flint_printf("\n");
390+
arb_printd(u, 19); flint_printf("\n");
391+
flint_abort();
392+
}
393+
394+
error = arb_set_str(t, testdata_rounding[i], 24);
395+
396+
x = strtof(testdata_rounding[i], NULL);
397+
arf_set_d(arb_midref(u), x);
398+
arf_mag_set_ulp(arb_radref(u), arb_midref(u), 25);
399+
400+
if (error != 0 || !arf_equal(arb_midref(t), arb_midref(u)) ||
401+
mag_cmp(arb_radref(t), arb_radref(u)) > 0)
402+
{
403+
flint_printf("FAIL (valid input): %s\n", testdata_rounding[i]);
404+
arb_printd(t, 19); flint_printf("\n");
405+
arb_printd(u, 19); flint_printf("\n");
406+
flint_abort();
407+
}
408+
}
409+
294410
arb_clear(t);
295411
arb_clear(u);
296412
arb_clear(v);

src/python/flint_ctypes.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4407,9 +4407,9 @@ def expm1(self):
44074407
Exponential function minus 1.
44084408
44094409
>>> RR("1e-10").expm1()
4410-
[1.000000000050000e-10 +/- 3.86e-26]
4410+
[1.000000000050000e-10 +/- 1.69e-26]
44114411
>>> CC(RR("1e-10")).expm1()
4412-
[1.000000000050000e-10 +/- 3.86e-26]
4412+
[1.000000000050000e-10 +/- 1.69e-26]
44134413
>>> RF("1e-10").expm1()
44144414
1.000000000050000e-10
44154415
>>> CF(RF("1e-10")).expm1()

0 commit comments

Comments
 (0)