diff options
| author | Paul Eggert | 1997-01-11 17:44:06 +0000 |
|---|---|---|
| committer | Paul Eggert | 1997-01-11 17:44:06 +0000 |
| commit | acbbacbe534d4b537ab6ecc242e4f0edd681fe7f (patch) | |
| tree | f66e93a588f83673635bee446bd34b6dc4f33df6 /src/floatfns.c | |
| parent | ec3bbd7d6b3880754b059b7605b17a106e5c1297 (diff) | |
| download | emacs-acbbacbe534d4b537ab6ecc242e4f0edd681fe7f.tar.gz emacs-acbbacbe534d4b537ab6ecc242e4f0edd681fe7f.zip | |
(rounding_driver): New function for systematic support of
2-argument rounding functions, so that `floor' isn't the only one
that supports 2 arguments.
(Fceiling, Ffloor, Fround, Ftruncate): Use it.
(ceiling2, floor2, round2, truncate2, double_identity): New functions.
(syms_of_floatfns): Define ceiling, round, and truncate even if
LISP_FLOAT_TYPE is not defined.
Diffstat (limited to 'src/floatfns.c')
| -rw-r--r-- | src/floatfns.c | 182 |
1 files changed, 107 insertions, 75 deletions
diff --git a/src/floatfns.c b/src/floatfns.c index 452bdc2ea54..1518006c5b2 100644 --- a/src/floatfns.c +++ b/src/floatfns.c | |||
| @@ -722,34 +722,17 @@ This is the same as the exponent of a float.") | |||
| 722 | return val; | 722 | return val; |
| 723 | } | 723 | } |
| 724 | 724 | ||
| 725 | /* the rounding functions */ | ||
| 726 | |||
| 727 | DEFUN ("ceiling", Fceiling, Sceiling, 1, 1, 0, | ||
| 728 | "Return the smallest integer no less than ARG. (Round toward +inf.)") | ||
| 729 | (arg) | ||
| 730 | register Lisp_Object arg; | ||
| 731 | { | ||
| 732 | CHECK_NUMBER_OR_FLOAT (arg, 0); | ||
| 733 | |||
| 734 | if (FLOATP (arg)) | ||
| 735 | { | ||
| 736 | double d; | ||
| 737 | |||
| 738 | IN_FLOAT (d = ceil (XFLOAT (arg)->data), "ceiling", arg); | ||
| 739 | FLOAT_TO_INT (d, arg, "ceiling", arg); | ||
| 740 | } | ||
| 741 | |||
| 742 | return arg; | ||
| 743 | } | ||
| 744 | |||
| 745 | #endif /* LISP_FLOAT_TYPE */ | 725 | #endif /* LISP_FLOAT_TYPE */ |
| 746 | 726 | ||
| 747 | 727 | ||
| 748 | DEFUN ("floor", Ffloor, Sfloor, 1, 2, 0, | 728 | /* the rounding functions */ |
| 749 | "Return the largest integer no greater than ARG. (Round towards -inf.)\n\ | 729 | |
| 750 | With optional DIVISOR, return the largest integer no greater than ARG/DIVISOR.") | 730 | static Lisp_Object |
| 751 | (arg, divisor) | 731 | rounding_driver (arg, divisor, double_round, int_round2, name) |
| 752 | register Lisp_Object arg, divisor; | 732 | register Lisp_Object arg, divisor; |
| 733 | double (*double_round) (); | ||
| 734 | EMACS_INT (*int_round2) (); | ||
| 735 | char *name; | ||
| 753 | { | 736 | { |
| 754 | CHECK_NUMBER_OR_FLOAT (arg, 0); | 737 | CHECK_NUMBER_OR_FLOAT (arg, 0); |
| 755 | 738 | ||
| @@ -769,8 +752,8 @@ With optional DIVISOR, return the largest integer no greater than ARG/DIVISOR.") | |||
| 769 | if (! IEEE_FLOATING_POINT && f2 == 0) | 752 | if (! IEEE_FLOATING_POINT && f2 == 0) |
| 770 | Fsignal (Qarith_error, Qnil); | 753 | Fsignal (Qarith_error, Qnil); |
| 771 | 754 | ||
| 772 | IN_FLOAT2 (f1 = floor (f1 / f2), "floor", arg, divisor); | 755 | IN_FLOAT2 (f1 = (*double_round) (f1 / f2), name, arg, divisor); |
| 773 | FLOAT_TO_INT2 (f1, arg, "floor", arg, divisor); | 756 | FLOAT_TO_INT2 (f1, arg, name, arg, divisor); |
| 774 | return arg; | 757 | return arg; |
| 775 | } | 758 | } |
| 776 | #endif | 759 | #endif |
| @@ -781,13 +764,7 @@ With optional DIVISOR, return the largest integer no greater than ARG/DIVISOR.") | |||
| 781 | if (i2 == 0) | 764 | if (i2 == 0) |
| 782 | Fsignal (Qarith_error, Qnil); | 765 | Fsignal (Qarith_error, Qnil); |
| 783 | 766 | ||
| 784 | /* With C's /, the result is implementation-defined if either operand | 767 | XSETINT (arg, (*int_round2) (i1, i2)); |
| 785 | is negative, so use only nonnegative operands. */ | ||
| 786 | i1 = (i2 < 0 | ||
| 787 | ? (i1 <= 0 ? -i1 / -i2 : -1 - ((i1 - 1) / -i2)) | ||
| 788 | : (i1 < 0 ? -1 - ((-1 - i1) / i2) : i1 / i2)); | ||
| 789 | |||
| 790 | XSETINT (arg, i1); | ||
| 791 | return arg; | 768 | return arg; |
| 792 | } | 769 | } |
| 793 | 770 | ||
| @@ -795,14 +772,107 @@ With optional DIVISOR, return the largest integer no greater than ARG/DIVISOR.") | |||
| 795 | if (FLOATP (arg)) | 772 | if (FLOATP (arg)) |
| 796 | { | 773 | { |
| 797 | double d; | 774 | double d; |
| 798 | IN_FLOAT (d = floor (XFLOAT (arg)->data), "floor", arg); | 775 | |
| 799 | FLOAT_TO_INT (d, arg, "floor", arg); | 776 | IN_FLOAT (d = (*double_round) (XFLOAT (arg)->data), name, arg); |
| 777 | FLOAT_TO_INT (d, arg, name, arg); | ||
| 800 | } | 778 | } |
| 801 | #endif | 779 | #endif |
| 802 | 780 | ||
| 803 | return arg; | 781 | return arg; |
| 804 | } | 782 | } |
| 805 | 783 | ||
| 784 | /* With C's /, the result is implementation-defined if either operand | ||
| 785 | is negative, so take care with negative operands in the following | ||
| 786 | integer functions. */ | ||
| 787 | |||
| 788 | static EMACS_INT | ||
| 789 | ceiling2 (i1, i2) | ||
| 790 | EMACS_INT i1, i2; | ||
| 791 | { | ||
| 792 | return (i2 < 0 | ||
| 793 | ? (i1 < 0 ? ((-1 - i1) / -i2) + 1 : - (i1 / -i2)) | ||
| 794 | : (i1 <= 0 ? - (-i1 / i2) : ((i1 - 1) / i2) + 1)); | ||
| 795 | } | ||
| 796 | |||
| 797 | static EMACS_INT | ||
| 798 | floor2 (i1, i2) | ||
| 799 | EMACS_INT i1, i2; | ||
| 800 | { | ||
| 801 | return (i2 < 0 | ||
| 802 | ? (i1 <= 0 ? -i1 / -i2 : -1 - ((i1 - 1) / -i2)) | ||
| 803 | : (i1 < 0 ? -1 - ((-1 - i1) / i2) : i1 / i2)); | ||
| 804 | } | ||
| 805 | |||
| 806 | static EMACS_INT | ||
| 807 | truncate2 (i1, i2) | ||
| 808 | EMACS_INT i1, i2; | ||
| 809 | { | ||
| 810 | return (i2 < 0 | ||
| 811 | ? (i1 < 0 ? -i1 / -i2 : - (i1 / -i2)) | ||
| 812 | : (i1 < 0 ? - (-i1 / i2) : i1 / i2)); | ||
| 813 | } | ||
| 814 | |||
| 815 | static EMACS_INT | ||
| 816 | round2 (i1, i2) | ||
| 817 | EMACS_INT i1, i2; | ||
| 818 | { | ||
| 819 | /* The C language's division operator gives us one remainder R, but | ||
| 820 | we want the remainder R1 on the other side of 0 if R1 is closer | ||
| 821 | to 0 than R is; because we want to round to even, we also want R1 | ||
| 822 | if R and R1 are the same distance from 0 and if C's quotient is | ||
| 823 | odd. */ | ||
| 824 | EMACS_INT q = i1 / i2; | ||
| 825 | EMACS_INT r = i1 % i2; | ||
| 826 | EMACS_INT abs_r = r < 0 ? -r : r; | ||
| 827 | EMACS_INT abs_r1 = (i2 < 0 ? -i2 : i2) - abs_r; | ||
| 828 | return q + (abs_r + (q & 1) <= abs_r1 ? 0 : (i2 ^ r) < 0 ? -1 : 1); | ||
| 829 | } | ||
| 830 | |||
| 831 | static double | ||
| 832 | double_identity (d) | ||
| 833 | double d; | ||
| 834 | { | ||
| 835 | return d; | ||
| 836 | } | ||
| 837 | |||
| 838 | DEFUN ("ceiling", Fceiling, Sceiling, 1, 2, 0, | ||
| 839 | "Return the smallest integer no less than ARG. (Round toward +inf.)\n\ | ||
| 840 | With optional DIVISOR, return the smallest integer no less than ARG/DIVISOR.") | ||
| 841 | (arg, divisor) | ||
| 842 | Lisp_Object arg, divisor; | ||
| 843 | { | ||
| 844 | return rounding_driver (arg, divisor, ceil, ceiling2, "ceiling"); | ||
| 845 | } | ||
| 846 | |||
| 847 | DEFUN ("floor", Ffloor, Sfloor, 1, 2, 0, | ||
| 848 | "Return the largest integer no greater than ARG. (Round towards -inf.)\n\ | ||
| 849 | With optional DIVISOR, return the largest integer no greater than ARG/DIVISOR.") | ||
| 850 | (arg, divisor) | ||
| 851 | Lisp_Object arg, divisor; | ||
| 852 | { | ||
| 853 | return rounding_driver (arg, divisor, floor, floor2, "floor"); | ||
| 854 | } | ||
| 855 | |||
| 856 | DEFUN ("round", Fround, Sround, 1, 2, 0, | ||
| 857 | "Return the nearest integer to ARG.\n\ | ||
| 858 | With optional DIVISOR, return the nearest integer to ARG/DIVISOR.") | ||
| 859 | (arg, divisor) | ||
| 860 | Lisp_Object arg, divisor; | ||
| 861 | { | ||
| 862 | return rounding_driver (arg, divisor, rint, round2, "round"); | ||
| 863 | } | ||
| 864 | |||
| 865 | DEFUN ("truncate", Ftruncate, Struncate, 1, 2, 0, | ||
| 866 | "Truncate a floating point number to an int.\n\ | ||
| 867 | Rounds ARG toward zero.\n\ | ||
| 868 | With optional DIVISOR, truncate ARG/DIVISOR.") | ||
| 869 | (arg, divisor) | ||
| 870 | Lisp_Object arg, divisor; | ||
| 871 | { | ||
| 872 | return rounding_driver (arg, divisor, double_identity, truncate2, | ||
| 873 | "truncate"); | ||
| 874 | } | ||
| 875 | |||
| 806 | #ifdef LISP_FLOAT_TYPE | 876 | #ifdef LISP_FLOAT_TYPE |
| 807 | 877 | ||
| 808 | Lisp_Object | 878 | Lisp_Object |
| @@ -823,44 +893,6 @@ fmod_float (x, y) | |||
| 823 | "mod", x, y); | 893 | "mod", x, y); |
| 824 | return make_float (f1); | 894 | return make_float (f1); |
| 825 | } | 895 | } |
| 826 | |||
| 827 | DEFUN ("round", Fround, Sround, 1, 1, 0, | ||
| 828 | "Return the nearest integer to ARG.") | ||
| 829 | (arg) | ||
| 830 | register Lisp_Object arg; | ||
| 831 | { | ||
| 832 | CHECK_NUMBER_OR_FLOAT (arg, 0); | ||
| 833 | |||
| 834 | if (FLOATP (arg)) | ||
| 835 | { | ||
| 836 | double d; | ||
| 837 | |||
| 838 | /* Screw the prevailing rounding mode. */ | ||
| 839 | IN_FLOAT (d = rint (XFLOAT (arg)->data), "round", arg); | ||
| 840 | FLOAT_TO_INT (d, arg, "round", arg); | ||
| 841 | } | ||
| 842 | |||
| 843 | return arg; | ||
| 844 | } | ||
| 845 | |||
| 846 | DEFUN ("truncate", Ftruncate, Struncate, 1, 1, 0, | ||
| 847 | "Truncate a floating point number to an int.\n\ | ||
| 848 | Rounds the value toward zero.") | ||
| 849 | (arg) | ||
| 850 | register Lisp_Object arg; | ||
| 851 | { | ||
| 852 | CHECK_NUMBER_OR_FLOAT (arg, 0); | ||
| 853 | |||
| 854 | if (FLOATP (arg)) | ||
| 855 | { | ||
| 856 | double d; | ||
| 857 | |||
| 858 | d = XFLOAT (arg)->data; | ||
| 859 | FLOAT_TO_INT (d, arg, "truncate", arg); | ||
| 860 | } | ||
| 861 | |||
| 862 | return arg; | ||
| 863 | } | ||
| 864 | 896 | ||
| 865 | /* It's not clear these are worth adding. */ | 897 | /* It's not clear these are worth adding. */ |
| 866 | 898 | ||
| @@ -1024,9 +1056,9 @@ syms_of_floatfns () | |||
| 1024 | defsubr (&Sabs); | 1056 | defsubr (&Sabs); |
| 1025 | defsubr (&Sfloat); | 1057 | defsubr (&Sfloat); |
| 1026 | defsubr (&Slogb); | 1058 | defsubr (&Slogb); |
| 1059 | #endif /* LISP_FLOAT_TYPE */ | ||
| 1027 | defsubr (&Sceiling); | 1060 | defsubr (&Sceiling); |
| 1061 | defsubr (&Sfloor); | ||
| 1028 | defsubr (&Sround); | 1062 | defsubr (&Sround); |
| 1029 | defsubr (&Struncate); | 1063 | defsubr (&Struncate); |
| 1030 | #endif /* LISP_FLOAT_TYPE */ | ||
| 1031 | defsubr (&Sfloor); | ||
| 1032 | } | 1064 | } |