Skip to content
GitLab
Projects
Groups
Snippets
/
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Sign in
Toggle navigation
Menu
Open sidebar
TASTE
uPython-mirror
Commits
8594ce22
Commit
8594ce22
authored
Sep 13, 2014
by
Damien George
Browse files
py: Implement divmod, % and proper // for floating point.
Tested and working on unix and pyboard.
parent
5c678349
Changes
8
Hide whitespace changes
Inline
Side-by-side
lib/libm/fmodf.c
0 → 100644
View file @
8594ce22
/*****************************************************************************/
/*****************************************************************************/
// fmodf from musl-0.9.15
/*****************************************************************************/
/*****************************************************************************/
#include
"libm.h"
float
fmodf
(
float
x
,
float
y
)
{
union
{
float
f
;
uint32_t
i
;}
ux
=
{
x
},
uy
=
{
y
};
int
ex
=
ux
.
i
>>
23
&
0xff
;
int
ey
=
uy
.
i
>>
23
&
0xff
;
uint32_t
sx
=
ux
.
i
&
0x80000000
;
uint32_t
i
;
uint32_t
uxi
=
ux
.
i
;
if
(
uy
.
i
<<
1
==
0
||
isnan
(
y
)
||
ex
==
0xff
)
return
(
x
*
y
)
/
(
x
*
y
);
if
(
uxi
<<
1
<=
uy
.
i
<<
1
)
{
if
(
uxi
<<
1
==
uy
.
i
<<
1
)
return
0
*
x
;
return
x
;
}
/* normalize x and y */
if
(
!
ex
)
{
for
(
i
=
uxi
<<
9
;
i
>>
31
==
0
;
ex
--
,
i
<<=
1
);
uxi
<<=
-
ex
+
1
;
}
else
{
uxi
&=
-
1U
>>
9
;
uxi
|=
1U
<<
23
;
}
if
(
!
ey
)
{
for
(
i
=
uy
.
i
<<
9
;
i
>>
31
==
0
;
ey
--
,
i
<<=
1
);
uy
.
i
<<=
-
ey
+
1
;
}
else
{
uy
.
i
&=
-
1U
>>
9
;
uy
.
i
|=
1U
<<
23
;
}
/* x mod y */
for
(;
ex
>
ey
;
ex
--
)
{
i
=
uxi
-
uy
.
i
;
if
(
i
>>
31
==
0
)
{
if
(
i
==
0
)
return
0
*
x
;
uxi
=
i
;
}
uxi
<<=
1
;
}
i
=
uxi
-
uy
.
i
;
if
(
i
>>
31
==
0
)
{
if
(
i
==
0
)
return
0
*
x
;
uxi
=
i
;
}
for
(;
uxi
>>
23
==
0
;
uxi
<<=
1
,
ex
--
);
/* scale result up */
if
(
ex
>
0
)
{
uxi
-=
1U
<<
23
;
uxi
|=
(
uint32_t
)
ex
<<
23
;
}
else
{
uxi
>>=
-
ex
+
1
;
}
uxi
|=
sx
;
ux
.
i
=
uxi
;
return
ux
.
f
;
}
lib/libm/math.c
View file @
8594ce22
...
...
@@ -117,7 +117,6 @@ float acoshf(float x) { return 0.0; }
float
asinhf
(
float
x
)
{
return
0
.
0
;
}
float
atanhf
(
float
x
)
{
return
0
.
0
;
}
float
tanf
(
float
x
)
{
return
0
.
0
;
}
float
fmodf
(
float
x
,
float
y
)
{
return
0
.
0
;
}
float
tgammaf
(
float
x
)
{
return
0
.
0
;
}
float
lgammaf
(
float
x
)
{
return
0
.
0
;
}
float
erff
(
float
x
)
{
return
0
.
0
;
}
...
...
py/builtin.c
View file @
8594ce22
...
...
@@ -242,13 +242,32 @@ STATIC mp_obj_t mp_builtin_dir(mp_uint_t n_args, const mp_obj_t *args) {
MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN
(
mp_builtin_dir_obj
,
0
,
1
,
mp_builtin_dir
);
STATIC
mp_obj_t
mp_builtin_divmod
(
mp_obj_t
o1_in
,
mp_obj_t
o2_in
)
{
// TODO handle big int
if
(
MP_OBJ_IS_SMALL_INT
(
o1_in
)
&&
MP_OBJ_IS_SMALL_INT
(
o2_in
))
{
mp_int_t
i1
=
MP_OBJ_SMALL_INT_VALUE
(
o1_in
);
mp_int_t
i2
=
MP_OBJ_SMALL_INT_VALUE
(
o2_in
);
if
(
i2
==
0
)
{
zero_division_error:
nlr_raise
(
mp_obj_new_exception_msg
(
&
mp_type_ZeroDivisionError
,
"division by zero"
));
}
mp_obj_t
args
[
2
];
args
[
0
]
=
MP_OBJ_NEW_SMALL_INT
(
i1
/
i2
);
args
[
1
]
=
MP_OBJ_NEW_SMALL_INT
(
i1
%
i2
);
return
mp_obj_new_tuple
(
2
,
args
);
#if MICROPY_PY_BUILTINS_FLOAT
}
else
if
(
MP_OBJ_IS_TYPE
(
o1_in
,
&
mp_type_float
)
||
MP_OBJ_IS_TYPE
(
o2_in
,
&
mp_type_float
))
{
mp_float_t
f1
=
mp_obj_get_float
(
o1_in
);
mp_float_t
f2
=
mp_obj_get_float
(
o2_in
);
if
(
f2
==
0
.
0
)
{
goto
zero_division_error
;
}
mp_obj_float_divmod
(
&
f1
,
&
f2
);
mp_obj_t
tuple
[
2
]
=
{
mp_obj_new_float
(
f1
),
mp_obj_new_float
(
f2
),
};
return
mp_obj_new_tuple
(
2
,
tuple
);
#endif
}
else
{
nlr_raise
(
mp_obj_new_exception_msg_varg
(
&
mp_type_TypeError
,
"unsupported operand type(s) for divmod(): '%s' and '%s'"
,
mp_obj_get_type_str
(
o1_in
),
mp_obj_get_type_str
(
o2_in
)));
}
...
...
py/obj.h
View file @
8594ce22
...
...
@@ -487,6 +487,7 @@ typedef struct _mp_obj_float_t {
}
mp_obj_float_t
;
mp_float_t
mp_obj_float_get
(
mp_obj_t
self_in
);
mp_obj_t
mp_obj_float_binary_op
(
mp_uint_t
op
,
mp_float_t
lhs_val
,
mp_obj_t
rhs
);
// can return MP_OBJ_NULL if op not supported
void
mp_obj_float_divmod
(
mp_float_t
*
x
,
mp_float_t
*
y
);
// complex
void
mp_obj_complex_get
(
mp_obj_t
self_in
,
mp_float_t
*
real
,
mp_float_t
*
imag
);
...
...
py/objfloat.c
View file @
8594ce22
...
...
@@ -143,14 +143,16 @@ mp_obj_t mp_obj_float_binary_op(mp_uint_t op, mp_float_t lhs_val, mp_obj_t rhs_i
case
MP_BINARY_OP_INPLACE_SUBTRACT
:
lhs_val
-=
rhs_val
;
break
;
case
MP_BINARY_OP_MULTIPLY
:
case
MP_BINARY_OP_INPLACE_MULTIPLY
:
lhs_val
*=
rhs_val
;
break
;
// TODO: verify that C floor matches Python semantics
case
MP_BINARY_OP_FLOOR_DIVIDE
:
case
MP_BINARY_OP_INPLACE_FLOOR_DIVIDE
:
if
(
rhs_val
==
0
)
{
zero_division_error:
nlr_raise
(
mp_obj_new_exception_msg
(
&
mp_type_ZeroDivisionError
,
"
float
division by zero"
));
nlr_raise
(
mp_obj_new_exception_msg
(
&
mp_type_ZeroDivisionError
,
"division by zero"
));
}
lhs_val
=
MICROPY_FLOAT_C_FUN
(
floor
)(
lhs_val
/
rhs_val
);
// Python specs require that x == (x//y)*y + (x%y) so we must
// call divmod to compute the correct floor division, which
// returns the floor divide in lhs_val.
mp_obj_float_divmod
(
&
lhs_val
,
&
rhs_val
);
break
;
case
MP_BINARY_OP_TRUE_DIVIDE
:
case
MP_BINARY_OP_INPLACE_TRUE_DIVIDE
:
...
...
@@ -159,6 +161,21 @@ mp_obj_t mp_obj_float_binary_op(mp_uint_t op, mp_float_t lhs_val, mp_obj_t rhs_i
}
lhs_val
/=
rhs_val
;
break
;
case
MP_BINARY_OP_MODULO
:
case
MP_BINARY_OP_INPLACE_MODULO
:
if
(
rhs_val
==
0
)
{
goto
zero_division_error
;
}
lhs_val
=
MICROPY_FLOAT_C_FUN
(
fmod
)(
lhs_val
,
rhs_val
);
// Python specs require that mod has same sign as second operand
if
(
lhs_val
==
0
.
0
)
{
lhs_val
=
MICROPY_FLOAT_C_FUN
(
copysign
)(
0
.
0
,
rhs_val
);
}
else
{
if
((
lhs_val
<
0
.
0
)
!=
(
rhs_val
<
0
.
0
))
{
lhs_val
+=
rhs_val
;
}
}
break
;
case
MP_BINARY_OP_POWER
:
case
MP_BINARY_OP_INPLACE_POWER
:
lhs_val
=
MICROPY_FLOAT_C_FUN
(
pow
)(
lhs_val
,
rhs_val
);
break
;
case
MP_BINARY_OP_LESS
:
return
MP_BOOL
(
lhs_val
<
rhs_val
);
...
...
@@ -173,4 +190,39 @@ mp_obj_t mp_obj_float_binary_op(mp_uint_t op, mp_float_t lhs_val, mp_obj_t rhs_i
return
mp_obj_new_float
(
lhs_val
);
}
void
mp_obj_float_divmod
(
mp_float_t
*
x
,
mp_float_t
*
y
)
{
// logic here follows that of CPython
// https://docs.python.org/3/reference/expressions.html#binary-arithmetic-operations
// x == (x//y)*y + (x%y)
// divmod(x, y) == (x//y, x%y)
mp_float_t
mod
=
MICROPY_FLOAT_C_FUN
(
fmod
)(
*
x
,
*
y
);
mp_float_t
div
=
(
*
x
-
mod
)
/
*
y
;
// Python specs require that mod has same sign as second operand
if
(
mod
==
0
.
0
)
{
mod
=
MICROPY_FLOAT_C_FUN
(
copysign
)(
0
.
0
,
*
y
);
}
else
{
if
((
mod
<
0
.
0
)
!=
(
*
y
<
0
.
0
))
{
mod
+=
*
y
;
div
-=
1
.
0
;
}
}
mp_float_t
floordiv
;
if
(
div
==
0
.
0
)
{
// if division is zero, take the correct sign of zero
floordiv
=
MICROPY_FLOAT_C_FUN
(
copysign
)(
0
.
0
,
*
x
/
*
y
);
}
else
{
// Python specs require that x == (x//y)*y + (x%y)
floordiv
=
MICROPY_FLOAT_C_FUN
(
floor
)(
div
);
if
(
div
-
floordiv
>
0
.
5
)
{
floordiv
+=
1
.
0
;
}
}
// return results
*
x
=
floordiv
;
*
y
=
mod
;
}
#endif // MICROPY_PY_BUILTINS_FLOAT
stmhal/Makefile
View file @
8594ce22
...
...
@@ -67,6 +67,7 @@ SRC_LIB = $(addprefix lib/,\
libm/asinfacosf.c
\
libm/atanf.c
\
libm/atan2f.c
\
libm/fmodf.c
\
)
SRC_C
=
\
...
...
tests/float/modulo.py
deleted
100644 → 0
View file @
5c678349
# check modulo matches python definition
# TODO we currenty fail with this
if
False
:
print
(
1.23456
%
0.7
)
print
(
-
1.23456
%
0.7
)
print
(
1.23456
%
-
0.7
)
print
(
-
1.23456
%
-
0.7
)
a
=
1.23456
b
=
0.7
print
(
a
%
b
)
print
(
a
%
-
b
)
print
(
-
a
%
b
)
print
(
-
a
%
-
b
)
tests/run-tests
View file @
8594ce22
...
...
@@ -33,6 +33,10 @@ def run_tests(pyb, tests, args):
if
os
.
getenv
(
'TRAVIS'
)
==
'true'
:
skip_tests
.
add
(
'basics/memoryerror.py'
)
# Some tests shouldn't be run on pyboard
if
pyb
is
not
None
:
skip_tests
.
add
(
'float/float_divmod.py'
)
# tested by float/float_divmod_relaxed.py instead
# Some tests are known to fail with native emitter
# Remove them from the below when they work
if
args
.
emit
==
'native'
:
...
...
Write
Preview
Supports
Markdown
0%
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment