Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commita96ad31

Browse files
gh-94906: Support multiple steps in math.nextafter
1 parent1c0a9c5 commita96ad31

File tree

9 files changed

+139
-17
lines changed

9 files changed

+139
-17
lines changed

‎Doc/library/math.rst‎

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -224,9 +224,9 @@ Number-theoretic and representation functions
224224
of *x* and are floats.
225225

226226

227-
..function::nextafter(x, y)
227+
..function::nextafter(x, y, /, *, steps=1)
228228

229-
Return thenextfloating-point value after *x* towards *y*.
229+
Return the floating-point value *steps* steps after *x* towards *y*.
230230

231231
If *x* is equal to *y*, return *y*.
232232

@@ -239,6 +239,9 @@ Number-theoretic and representation functions
239239

240240
See also:func:`math.ulp`.
241241

242+
..versionchanged::3.12
243+
Added the *steps* argument.
244+
242245
..versionadded::3.9
243246

244247
..function::perm(n, k=None)

‎Include/internal/pycore_global_objects_fini_generated.h‎

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more aboutcustomizing how changed files appear on GitHub.

‎Include/internal/pycore_global_strings.h‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -657,6 +657,7 @@ struct _Py_global_strings {
657657
STRUCT_FOR_ID(stdin)
658658
STRUCT_FOR_ID(stdout)
659659
STRUCT_FOR_ID(step)
660+
STRUCT_FOR_ID(steps)
660661
STRUCT_FOR_ID(store_name)
661662
STRUCT_FOR_ID(strategy)
662663
STRUCT_FOR_ID(strftime)

‎Include/internal/pycore_runtime_init_generated.h‎

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more aboutcustomizing how changed files appear on GitHub.

‎Include/internal/pycore_unicodeobject_generated.h‎

Lines changed: 3 additions & 0 deletions
Some generated files are not rendered by default. Learn more aboutcustomizing how changed files appear on GitHub.

‎Lib/test/test_math.py‎

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2296,11 +2296,20 @@ def test_nextafter(self):
22962296
float.fromhex('0x1.fffffffffffffp-1'))
22972297
self.assertEqual(math.nextafter(1.0,INF),
22982298
float.fromhex('0x1.0000000000001p+0'))
2299+
self.assertEqual(math.nextafter(1.0,-INF,steps=1),
2300+
float.fromhex('0x1.fffffffffffffp-1'))
2301+
self.assertEqual(math.nextafter(1.0,INF,steps=1),
2302+
float.fromhex('0x1.0000000000001p+0'))
2303+
self.assertEqual(math.nextafter(1.0,-INF,steps=3),
2304+
float.fromhex('0x1.ffffffffffffdp-1'))
2305+
self.assertEqual(math.nextafter(1.0,INF,steps=3),
2306+
float.fromhex('0x1.0000000000003p+0'))
22992307

23002308
# x == y: y is returned
2301-
self.assertEqual(math.nextafter(2.0,2.0),2.0)
2302-
self.assertEqualSign(math.nextafter(-0.0,+0.0),+0.0)
2303-
self.assertEqualSign(math.nextafter(+0.0,-0.0),-0.0)
2309+
forstepsinrange(1,5):
2310+
self.assertEqual(math.nextafter(2.0,2.0,steps=steps),2.0)
2311+
self.assertEqualSign(math.nextafter(-0.0,+0.0,steps=steps),+0.0)
2312+
self.assertEqualSign(math.nextafter(+0.0,-0.0,steps=steps),-0.0)
23042313

23052314
# around 0.0
23062315
smallest_subnormal=sys.float_info.min*sys.float_info.epsilon
@@ -2325,6 +2334,11 @@ def test_nextafter(self):
23252334
self.assertIsNaN(math.nextafter(1.0,NAN))
23262335
self.assertIsNaN(math.nextafter(NAN,NAN))
23272336

2337+
self.assertEqual(1.0,math.nextafter(1.0,INF,steps=0))
2338+
withself.assertRaises(ValueError):
2339+
math.nextafter(1.0,INF,steps=-1)
2340+
2341+
23282342
@requires_IEEE_754
23292343
deftest_ulp(self):
23302344
self.assertEqual(math.ulp(1.0),sys.float_info.epsilon)
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Support multiple steps in:func:`math.nextafter`. Patch by Shantanu Jain and Matthias Gorgens.

‎Modules/clinic/mathmodule.c.h‎

Lines changed: 45 additions & 8 deletions
Some generated files are not rendered by default. Learn more aboutcustomizing how changed files appear on GitHub.

‎Modules/mathmodule.c‎

Lines changed: 65 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3893,13 +3893,15 @@ math.nextafter
38933893
x: double
38943894
y: double
38953895
/
3896+
*
3897+
steps: int = 1
38963898
3897-
Return thenextfloating-point value after x towards y.
3899+
Return the floating-point value the given number of steps after x towards y.
38983900
[clinic start generated code]*/
38993901

39003902
staticPyObject*
3901-
math_nextafter_impl(PyObject*module,doublex,doubley)
3902-
/*[clinic end generated code: output=750c8266c1c540ce input=02b2d50cd1d9f9b6]*/
3903+
math_nextafter_impl(PyObject*module,doublex,doubley,intsteps)
3904+
/*[clinic end generated code: output=14190eb869199e5a input=a794e7a79768ee25]*/
39033905
{
39043906
#if defined(_AIX)
39053907
if (x==y) {
@@ -3914,7 +3916,66 @@ math_nextafter_impl(PyObject *module, double x, double y)
39143916
returnPyFloat_FromDouble(y);
39153917
}
39163918
#endif
3917-
returnPyFloat_FromDouble(nextafter(x,y));
3919+
// fast path:
3920+
if (steps==1) {
3921+
returnPyFloat_FromDouble(nextafter(x,y));
3922+
}
3923+
if (steps<0) {
3924+
PyErr_SetString(PyExc_ValueError,"steps must be >= 0");
3925+
returnNULL;
3926+
}
3927+
if (steps==0)
3928+
returnPyFloat_FromDouble(x);
3929+
if (Py_IS_NAN(x)||Py_IS_NAN(y))
3930+
returnPyFloat_FromDouble(x+y);
3931+
3932+
uint64_tusteps=steps;
3933+
3934+
unionpun {doublef;uint64_ti;};
3935+
unionpunux= {x},uy= {y};
3936+
if(ux.i==uy.i) {
3937+
returnPyFloat_FromDouble(x);
3938+
}
3939+
3940+
constuint64_tsign_bit=1ULL<<63;
3941+
3942+
uint64_tax=ux.i& ~sign_bit;
3943+
uint64_tay=uy.i& ~sign_bit;
3944+
3945+
// opposite signs
3946+
if (((ux.i ^uy.i)&sign_bit)) {
3947+
if (ax+ay <=usteps) {
3948+
returnPyFloat_FromDouble(uy.f);
3949+
// We can't use <= here, because of +0.0 vs 0.0
3950+
}elseif (ax<usteps) {
3951+
unionpunresult= {.i= (uy.i&sign_bit) | (usteps-ax)};
3952+
returnPyFloat_FromDouble(result.f);
3953+
}else {
3954+
ux.i-=usteps;
3955+
returnPyFloat_FromDouble(ux.f);
3956+
}
3957+
// same sign now.
3958+
// going down:
3959+
}elseif (ax>ay) {
3960+
// going too far:
3961+
// the addition is not UB,
3962+
// because we have an extra bit at the top of ax and usteps.
3963+
if (ax >=ay+usteps) {
3964+
ux.i-=usteps;
3965+
returnPyFloat_FromDouble(ux.f);
3966+
}else {
3967+
returnPyFloat_FromDouble(uy.f);
3968+
}
3969+
}else {// go up in magnitude. same sign.
3970+
// the addition is not UB,
3971+
// because we have an extra bit at the top of ax and usteps.
3972+
if (ax+usteps <=ay) {
3973+
ux.i+=usteps;
3974+
returnPyFloat_FromDouble(ux.f);
3975+
}else {
3976+
returnPyFloat_FromDouble(uy.f);
3977+
}
3978+
}
39183979
}
39193980

39203981

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp