Mercurial > emacs
comparison src/floatfns.c @ 16857:bdafa1f28a64
(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.
| author | Paul Eggert <eggert@twinsun.com> |
|---|---|
| date | Sat, 11 Jan 1997 17:44:06 +0000 |
| parents | 8907c00c0cc6 |
| children | a6b5ec9a51b4 |
comparison
equal
deleted
inserted
replaced
| 16856:f838ff9a4d39 | 16857:bdafa1f28a64 |
|---|---|
| 720 } | 720 } |
| 721 XSETINT (val, value); | 721 XSETINT (val, value); |
| 722 return val; | 722 return val; |
| 723 } | 723 } |
| 724 | 724 |
| 725 #endif /* LISP_FLOAT_TYPE */ | |
| 726 | |
| 727 | |
| 725 /* the rounding functions */ | 728 /* the rounding functions */ |
| 726 | 729 |
| 727 DEFUN ("ceiling", Fceiling, Sceiling, 1, 1, 0, | 730 static Lisp_Object |
| 728 "Return the smallest integer no less than ARG. (Round toward +inf.)") | 731 rounding_driver (arg, divisor, double_round, int_round2, name) |
| 729 (arg) | 732 register Lisp_Object arg, divisor; |
| 730 register Lisp_Object arg; | 733 double (*double_round) (); |
| 734 EMACS_INT (*int_round2) (); | |
| 735 char *name; | |
| 731 { | 736 { |
| 732 CHECK_NUMBER_OR_FLOAT (arg, 0); | 737 CHECK_NUMBER_OR_FLOAT (arg, 0); |
| 733 | 738 |
| 739 if (! NILP (divisor)) | |
| 740 { | |
| 741 EMACS_INT i1, i2; | |
| 742 | |
| 743 CHECK_NUMBER_OR_FLOAT (divisor, 1); | |
| 744 | |
| 745 #ifdef LISP_FLOAT_TYPE | |
| 746 if (FLOATP (arg) || FLOATP (divisor)) | |
| 747 { | |
| 748 double f1, f2; | |
| 749 | |
| 750 f1 = FLOATP (arg) ? XFLOAT (arg)->data : XINT (arg); | |
| 751 f2 = (FLOATP (divisor) ? XFLOAT (divisor)->data : XINT (divisor)); | |
| 752 if (! IEEE_FLOATING_POINT && f2 == 0) | |
| 753 Fsignal (Qarith_error, Qnil); | |
| 754 | |
| 755 IN_FLOAT2 (f1 = (*double_round) (f1 / f2), name, arg, divisor); | |
| 756 FLOAT_TO_INT2 (f1, arg, name, arg, divisor); | |
| 757 return arg; | |
| 758 } | |
| 759 #endif | |
| 760 | |
| 761 i1 = XINT (arg); | |
| 762 i2 = XINT (divisor); | |
| 763 | |
| 764 if (i2 == 0) | |
| 765 Fsignal (Qarith_error, Qnil); | |
| 766 | |
| 767 XSETINT (arg, (*int_round2) (i1, i2)); | |
| 768 return arg; | |
| 769 } | |
| 770 | |
| 771 #ifdef LISP_FLOAT_TYPE | |
| 734 if (FLOATP (arg)) | 772 if (FLOATP (arg)) |
| 735 { | 773 { |
| 736 double d; | 774 double d; |
| 737 | 775 |
| 738 IN_FLOAT (d = ceil (XFLOAT (arg)->data), "ceiling", arg); | 776 IN_FLOAT (d = (*double_round) (XFLOAT (arg)->data), name, arg); |
| 739 FLOAT_TO_INT (d, arg, "ceiling", arg); | 777 FLOAT_TO_INT (d, arg, name, arg); |
| 740 } | 778 } |
| 779 #endif | |
| 741 | 780 |
| 742 return arg; | 781 return arg; |
| 743 } | 782 } |
| 744 | 783 |
| 745 #endif /* LISP_FLOAT_TYPE */ | 784 /* With C's /, the result is implementation-defined if either operand |
| 746 | 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 } | |
| 747 | 846 |
| 748 DEFUN ("floor", Ffloor, Sfloor, 1, 2, 0, | 847 DEFUN ("floor", Ffloor, Sfloor, 1, 2, 0, |
| 749 "Return the largest integer no greater than ARG. (Round towards -inf.)\n\ | 848 "Return the largest integer no greater than ARG. (Round towards -inf.)\n\ |
| 750 With optional DIVISOR, return the largest integer no greater than ARG/DIVISOR.") | 849 With optional DIVISOR, return the largest integer no greater than ARG/DIVISOR.") |
| 751 (arg, divisor) | 850 (arg, divisor) |
| 752 register Lisp_Object arg, divisor; | 851 Lisp_Object arg, divisor; |
| 753 { | 852 { |
| 754 CHECK_NUMBER_OR_FLOAT (arg, 0); | 853 return rounding_driver (arg, divisor, floor, floor2, "floor"); |
| 755 | 854 } |
| 756 if (! NILP (divisor)) | 855 |
| 757 { | 856 DEFUN ("round", Fround, Sround, 1, 2, 0, |
| 758 EMACS_INT i1, i2; | 857 "Return the nearest integer to ARG.\n\ |
| 759 | 858 With optional DIVISOR, return the nearest integer to ARG/DIVISOR.") |
| 760 CHECK_NUMBER_OR_FLOAT (divisor, 1); | 859 (arg, divisor) |
| 761 | 860 Lisp_Object arg, divisor; |
| 762 #ifdef LISP_FLOAT_TYPE | 861 { |
| 763 if (FLOATP (arg) || FLOATP (divisor)) | 862 return rounding_driver (arg, divisor, rint, round2, "round"); |
| 764 { | 863 } |
| 765 double f1, f2; | 864 |
| 766 | 865 DEFUN ("truncate", Ftruncate, Struncate, 1, 2, 0, |
| 767 f1 = FLOATP (arg) ? XFLOAT (arg)->data : XINT (arg); | 866 "Truncate a floating point number to an int.\n\ |
| 768 f2 = (FLOATP (divisor) ? XFLOAT (divisor)->data : XINT (divisor)); | 867 Rounds ARG toward zero.\n\ |
| 769 if (! IEEE_FLOATING_POINT && f2 == 0) | 868 With optional DIVISOR, truncate ARG/DIVISOR.") |
| 770 Fsignal (Qarith_error, Qnil); | 869 (arg, divisor) |
| 771 | 870 Lisp_Object arg, divisor; |
| 772 IN_FLOAT2 (f1 = floor (f1 / f2), "floor", arg, divisor); | 871 { |
| 773 FLOAT_TO_INT2 (f1, arg, "floor", arg, divisor); | 872 return rounding_driver (arg, divisor, double_identity, truncate2, |
| 774 return arg; | 873 "truncate"); |
| 775 } | |
| 776 #endif | |
| 777 | |
| 778 i1 = XINT (arg); | |
| 779 i2 = XINT (divisor); | |
| 780 | |
| 781 if (i2 == 0) | |
| 782 Fsignal (Qarith_error, Qnil); | |
| 783 | |
| 784 /* With C's /, the result is implementation-defined if either operand | |
| 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; | |
| 792 } | |
| 793 | |
| 794 #ifdef LISP_FLOAT_TYPE | |
| 795 if (FLOATP (arg)) | |
| 796 { | |
| 797 double d; | |
| 798 IN_FLOAT (d = floor (XFLOAT (arg)->data), "floor", arg); | |
| 799 FLOAT_TO_INT (d, arg, "floor", arg); | |
| 800 } | |
| 801 #endif | |
| 802 | |
| 803 return arg; | |
| 804 } | 874 } |
| 805 | 875 |
| 806 #ifdef LISP_FLOAT_TYPE | 876 #ifdef LISP_FLOAT_TYPE |
| 807 | 877 |
| 808 Lisp_Object | 878 Lisp_Object |
| 820 /* If the "remainder" comes out with the wrong sign, fix it. */ | 890 /* If the "remainder" comes out with the wrong sign, fix it. */ |
| 821 IN_FLOAT2 ((f1 = fmod (f1, f2), | 891 IN_FLOAT2 ((f1 = fmod (f1, f2), |
| 822 f1 = (f2 < 0 ? f1 > 0 : f1 < 0) ? f1 + f2 : f1), | 892 f1 = (f2 < 0 ? f1 > 0 : f1 < 0) ? f1 + f2 : f1), |
| 823 "mod", x, y); | 893 "mod", x, y); |
| 824 return make_float (f1); | 894 return make_float (f1); |
| 825 } | |
| 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 } | 895 } |
| 864 | 896 |
| 865 /* It's not clear these are worth adding. */ | 897 /* It's not clear these are worth adding. */ |
| 866 | 898 |
| 867 DEFUN ("fceiling", Ffceiling, Sfceiling, 1, 1, 0, | 899 DEFUN ("fceiling", Ffceiling, Sfceiling, 1, 1, 0, |
| 1022 defsubr (&Ssqrt); | 1054 defsubr (&Ssqrt); |
| 1023 | 1055 |
| 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 */ | 1064 } |
| 1031 defsubr (&Sfloor); | |
| 1032 } |
