1
Fork 0
mirror of git://git.sv.gnu.org/emacs.git synced 2025-12-30 00:51:50 -08:00
emacs/src/floatfns.c
Po Lu 85a078e785 Add support for the Haiku operating system and its window system
* .gitignore: Add binaries specific to Haiku.

* Makefie.in (HAVE_BE_APP): New variable.
(install-arch-dep): Install Emacs and Emacs.pdmp when
using Haiku.

* configure.ac: Detect and configure for Haiku and
various related configurations.
(be-app, be-freetype, be-cairo): New options.
(HAVE_BE_APP, HAIKU_OBJ, HAIKU_CXX_OBJ)
(HAIKU_LIBS, HAIKU_CFLAGS): New variables.
(HAIKU, HAVE_TINY_SPEED_T): New define.
(emacs_config_features): Add BE_APP.

* doc/emacs/Makefile.in (EMACSSOURCES): Add Haiku
appendix.

* doc/emacs/emacs.texi: Add Haiku appendix to menus and
include it.

* doc/emacs/haiku.texi: New Haiku appendix.

* doc/lispref/display.texi (Defining Faces, Window Systems):
Explain meaning of `haiku' as a window system identifier.
(haiku-use-system-tooltips): Explain meaning of system
tooltips on
Haiku.

* doc/lispref/frames.texi (Multiple Terminals): Explain
meaning of haiku as a display type.
(Frame Layout): Clarify section for Haiku frames.
(Size Parameters): Explain limitations of fullwidth and
fullheight on Haiku.
(Management Parameters): Explain limitations of
inhibiting double buffering on builds with Cairo,
and the inability of frames with no-accept-focus to
receive keyboard input on Haiku.
(Font and Color Parameters): Explain the different font
backends available on Haiku.
(Raising and Lowering): Explain that lowering and
restacking frames doesn't work on Haiku.
(Child Frames): Explain oddities of child frame
visibility on Haiku.

* doc/lispref/os.texi (System Environment): Explain
meaning of haiku.
* etc/MACHINES: Add appropriate notices for Haiku.
* etc/NEWS: Document changes.
* etc/PROBLEMS: Document font spacing bug on Haiku.

* lib-src/Makefile.in: Build be-resources binary on
Haiku.
(CXX, CXXFLAGS, NON_CXX_FLAGS, ALL_CXXFLAGS)
(HAVE_BE_APP, HAIKU_LIBS, HAIKU_CFLAGS): New variables.
(DONT_INSTALL): Add be-resources binary if on Haiku.
(be-resources): New target.

* lib-src/be_resources: Add helper binary for setting
resources on the Emacs application.

* lib-src/emacsclient.c (decode_options): Set
alt_display to "be" on Haiku.

* lisp/cus-edit.el (custom-button, custom-button-mouse)
(custom-button-unraised, custom-button-pressed): Update
face definitions for Haiku.

* lisp/cus-start.el: Add haiku-debug-on-fatal-error and
haiku-use-system-tooltips.

* lisp/faces.el (face-valid-attribute-values): Clarify
attribute comment for Haiku.
(tool-bar): Add appropriate toolbar color for Haiku.

* lisp/frame.el (haiku-frame-geometry)
(haiku-mouse-absolute-pixel-position)
(haiku-set-mouse-absolute-pixel-position)
(haiku-frame-edges)
(haiku-frame-list-z-order): New function declarations.

(frame-geometry, frame-edges)
(mouse-absolute-pixel-position)
(set-mouse-absolute-pixel-position)
(frame-list-z-order): Call appropriate window system
functions on Haiku.

(display-mouse-p, display-graphic-p)
(display-images-p, display-pixel-height)
(display-pixel-width, display-mm-height)
(display-mm-width, display-backing-store)
(display-save-under, display-planes)
(display-color-cells, display-visual-class): Update type
tests for Haiku.

* lisp/international/mule-cmds.el
(set-coding-system-map): Also
prevent set-terminal-coding-system from appearing in the menu
bar on Haiku.

* lisp/loadup.el: Load Haiku-specific files when built
with Haiku, and don't rename newly built Emacs on Haiku as BFS
doesn't support hard links.

* lisp/menu-bar.el (menu-bar-open): Add for Haiku.

* lisp/mwheel.el (mouse-wheel-down-event): Expect
wheel-up on Haiku.
(mouse-wheel-up-event): Expect wheel-down on Haiku.
(mouse-wheel-left-event): Expect wheel-left on Haiku.
(mouse-wheel-right-event): Expect wheel-right on Haiku.

* lisp/net/browse-url.el
(browse-url--browser-defcustom-type):
Add option for WebPositive.
(browse-url-webpositive-program): New variable.
(browse-url-default-program): Search for WebPositive.
(browse-url-webpositive): New function.

* lisp/net/eww.el (eww-form-submit, eww-form-file)
(eww-form-checkbox, eww-form-select): Define faces
appropriately for Haiku.

* lisp/term/haiku-win.el: New file.

* lisp/tooltip.el (menu-or-popup-active-p): New function
declaration.
(tooltip-show-help): Don't use tooltips on Haiku when a
menu is active.

* lisp/version.el (haiku-get-version-string): New
function declaration.
(emacs-version): Add Haiku version string if
appropriate.

* src/Makefile.in: Also produce binary named "Emacs"
with Haiku resources set.

(CXX, HAIKU_OBJ, HAIKU_CXX_OBJ, HAIKU_LIBS)
(HAIKU_CFLAGS, HAVE_BE_APP, NON_CXX_FLAGS)
(ALL_CXX_FLAGS): New variables.

(.SUFFIXES): Add .cc.
(.cc.o): New target.
(base_obj): Add Haiku C objects.
(doc_obj, obj): Split objects that should scanned for
documentation into doc_obj.
(SOME_MACHINE_OBJECTS): Add appropriate Haiku C objects.
(all): Depend on Emacs and Emacs.pdmp on Haiku.
(LIBES): Add Haiku libraries.
(gl-stamp)
($(etc)/DOC): Scan doc_obj instead of obj
(temacs$(EXEEXT): Use C++ linker on Haiku.
(ctagsfiles3): New variable.
(TAGS): Scan C++ files.

* src/alloc.c (garbage_collect): Mark Haiku display.

* src/dispextern.h (HAVE_NATIVE_TRANSFORMS): Also enable
on Haiku.
(struct image): Add fields for Haiku transforms.
(RGB_PIXEL_COLOR): Define to unsigned long on Haiku as
well.
(sit_for): Also check USABLE_SIGPOLL.
(init_display_interactive): Set initial window system to
Haiku on Haiku builds.

* src/emacs.c (main): Define Haiku syms and init haiku
clipboard.
(shut_down_emacs): Quit BApplication on Haiku and
trigger debug
on aborts if haiku_debug_on_fatal_error.
(Vsystem_type): Update docstring.

* src/fileio.c (next-read-file-uses-dialog-p): Enable on
Haiku.

* src/filelock.c (WTMP_FILE): Only define if BOOT_TIME
is also defined.

* src/floatfns.c (double_integer_scale): Work around
Haiku libroot brain damage.

* src/font.c (syms_of_font): Define appropriate font
driver symbols for Haiku builds with various options.

* src/font.h: Also enable ftcrfont on Haiku builds with
Cairo.
(font_data_structures_may_be_ill_formed): Also enable on
Haiku builds that have Cairo.

* src/frame.c (Fframep): Update doc-string for Haiku
builds and return haiku if appropriate.
(syms_of_frame): New symbol `haiku'.

* src/frame.h (struct frame): Add output data for Haiku.
(FRAME_HAIKU_P): New macro.
(FRAME_WINDOW_P): Test for Haiku frames as well.

* src/ftcrfont.c (RED_FROM_ULONG, GREEN_FROM_ULONG)
(BLUE_FROM_ULONG): New macros.
(ftcrfont_draw): Add haiku specific code for Haiku
builds with Cairo.

* src/ftfont.c (ftfont_open): Set face.
(ftfont_has_char, ftfont_text_extents): Work around
crash.
(syms_of_ftfont): New symbol `mono'.

* src/ftfont.h (struct font_info): Enable Cairo-specific
fields for Cairo builds on Haiku.

* src/haiku_draw_support.cc:
* src/haiku_font_support.cc:
* src/haiku_io.c:
* src/haiku_select.cc:
* src/haiku_support.cc:
* src/haiku_support.h:
* src/haikufns.c:
* src/haikufont.c:
* src/haikugui.h:
* src/haikuimage.c:
* src/haikumenu.c:
* src/haikuselect.c:
* src/haikuselect.h:
* src/haikuterm.c:
* src/haikuterm.h: Add new files for Haiku windowing
support.

* src/haiku.c: Add new files for Haiku operating system
support.

* src/image.c: Implement image transforms and native XPM
support
on Haiku.

(GET_PIXEL, PUT_PIXEL, NO_PIXMAP)
(PIX_MASK_RETAIN, PIX_MASK_DRAW)
(RGB_TO_ULONG, RED_FROM_ULONG, GREEN_FROM_ULONG)
(BLUE_FROM_ULONG, RED16_FROM_ULONG, GREEN16_FROM_ULONG)
(BLUE16_FROM_ULONG): Define to appropriate values on
Haiku.

(image_create_bitmap_from_data): Add Haiku support.
(image_create_bitmap_from_file): Add TODO on Haiku.
(free_bitmap_record): Free bitmap on Haiku.
(image_size_in_bytes): Implement for Haiku bitmaps.
(image_set_transform): Implement on Haiku.
(image_create_x_image_and_pixmap_1): Implement on Haiku,
24-bit or 1-bit only.
(image_destroy_x_image, image_get_x_image): Use correct
img and pixmap values on Haiku.
(lookup_rgb_color): Use correct macro on Haiku.
(image_to_emacs_colors): Implement on Haiku.
(image_disable_image): Disable on Haiku.
(image_can_use_native_api): Test for translator presence
on Haiku.
(native_image_load): Use translator on Haiku.
(imagemagick_load_image): Add Haiku-specific quirks.
(Fimage_transforms_p): Allow rotate90 on Haiku.
(image_types): Enable native XPM support on Haiku.
(syms_of_image): Enable XPM images on Haiku.

* src/keyboard.c (kbd_buffer_get_event)
(handle_async_input, handle_input_available_signal)
(handle_user_signal, Fset_input_interrupt_mode)
(init_keyboard): Check for USABLE_SIGPOLL along with
USABLE_SIGIO.

* src/lisp.h (pD): Work around broken Haiku headers.
(HAVE_EXT_MENU_BAR): Define on Haiku.
(handle_input_available_signal): Enable if we just have
SIGPOLL as well.

* src/menu.c (have_boxes): Return true on Haiku.
(single_menu_item): Enable toolkit menus on Haiku.
(find_and_call_menu_selection): Also enable on Haiku.

* src/process.c (keyboard_bit_set): Enable with only
usable SIGPOLL.
(wait_reading_process_output): Test for SIGPOLL as well
as SIGIO availability.

* src/sound.c (sound_perror, vox_open)
(vox_configure, vox_close): Enable for usable SIGPOLL as
well.

* src/sysdep.c (sys_subshell): Enable for usable SIGPOLL.
(reset_sigio): Make conditional on F_SETOWN.
(request_sigio, unrequest_sigio)
(emacs_sigaction_init): Also handle SIGPOLLs.
(init_sys_modes): Disable TCXONC usage on Haiku, as it
doesn't have any ttys other than pseudo ttys, which don't
support C-s/C-q flow control, and causes compiler warnings.
(speeds): Disable high speeds if HAVE_TINY_SPEED_T.

* src/termhooks.h (enum output_method): Add output_haiku.
(struct terminal): Add Haiku display info.
(TERMINAL_FONT_CACHE): Enable for Haiku.

* src/terminal.c (Fterminal_live_p): Return `haiku' if
appropriate.
* src/verbose.mk.in (AM_V_CXX, AM_V_CXXLD): New logging
variables.

* src/xdisp.c (redisplay_internal)
(note_mouse_highlight): Return on Haiku if a popup is activated.
(display_menu_bar): Return on Haiku if frame is a Haiku
frame.

* src/xfaces.c (GCGraphicsExposures): Enable correctly on Haiku.
(x_create_gc): Enable dummy GC code on Haiku.

* src/xfns.c (x-server-version, x-file-dialog): Add
Haiku specifics to doc strings.

* src/xterm.c (syms_of_xterm): Add Haiku information to
doc string.
2021-11-20 21:46:07 +08:00

657 lines
17 KiB
C
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/* Primitive operations on floating point for GNU Emacs Lisp interpreter.
Copyright (C) 1988, 1993-1994, 1999, 2001-2021 Free Software Foundation,
Inc.
Author: Wolfgang Rupprecht (according to ack.texi)
This file is part of GNU Emacs.
GNU Emacs is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or (at
your option) any later version.
GNU Emacs is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
/* C89 requires only the following math.h functions, and Emacs omits
the starred functions since we haven't found a use for them:
acos, asin, atan, atan2, ceil, cos, *cosh, exp, fabs, floor, fmod,
frexp, ldexp, log, log10 [via (log X 10)], *modf, pow, sin, *sinh,
sqrt, tan, *tanh.
C99 and C11 require the following math.h functions in addition to
the C89 functions. Of these, Emacs currently exports only the
starred ones to Lisp, since we haven't found a use for the others:
acosh, atanh, cbrt, *copysign, erf, erfc, exp2, expm1, fdim, fma,
fmax, fmin, fpclassify, hypot, ilogb, isfinite, isgreater,
isgreaterequal, isinf, isless, islessequal, islessgreater, *isnan,
isnormal, isunordered, lgamma, log1p, *log2 [via (log X 2)], *logb
(approximately), lrint/llrint, lround/llround, nan, nearbyint,
nextafter, nexttoward, remainder, remquo, *rint, round, scalbln,
scalbn, signbit, tgamma, *trunc.
*/
#include <config.h>
#include "lisp.h"
#include "bignum.h"
#include <math.h>
#include <count-leading-zeros.h>
/* Emacs needs proper handling of +/-inf; correct printing as well as
important packages depend on it. Make sure the user didn't specify
-ffinite-math-only, either directly or implicitly with -Ofast or
-ffast-math. */
#if defined __FINITE_MATH_ONLY__ && __FINITE_MATH_ONLY__
#error Emacs cannot be built with -ffinite-math-only
#endif
/* Check that X is a floating point number. */
static void
CHECK_FLOAT (Lisp_Object x)
{
CHECK_TYPE (FLOATP (x), Qfloatp, x);
}
/* Extract a Lisp number as a `double', or signal an error. */
double
extract_float (Lisp_Object num)
{
CHECK_NUMBER (num);
return XFLOATINT (num);
}
/* Trig functions. */
DEFUN ("acos", Facos, Sacos, 1, 1, 0,
doc: /* Return the inverse cosine of ARG. */)
(Lisp_Object arg)
{
double d = extract_float (arg);
d = acos (d);
return make_float (d);
}
DEFUN ("asin", Fasin, Sasin, 1, 1, 0,
doc: /* Return the inverse sine of ARG. */)
(Lisp_Object arg)
{
double d = extract_float (arg);
d = asin (d);
return make_float (d);
}
DEFUN ("atan", Fatan, Satan, 1, 2, 0,
doc: /* Return the inverse tangent of the arguments.
If only one argument Y is given, return the inverse tangent of Y.
If two arguments Y and X are given, return the inverse tangent of Y
divided by X, i.e. the angle in radians between the vector (X, Y)
and the x-axis. */)
(Lisp_Object y, Lisp_Object x)
{
double d = extract_float (y);
if (NILP (x))
d = atan (d);
else
{
double d2 = extract_float (x);
d = atan2 (d, d2);
}
return make_float (d);
}
DEFUN ("cos", Fcos, Scos, 1, 1, 0,
doc: /* Return the cosine of ARG. */)
(Lisp_Object arg)
{
double d = extract_float (arg);
d = cos (d);
return make_float (d);
}
DEFUN ("sin", Fsin, Ssin, 1, 1, 0,
doc: /* Return the sine of ARG. */)
(Lisp_Object arg)
{
double d = extract_float (arg);
d = sin (d);
return make_float (d);
}
DEFUN ("tan", Ftan, Stan, 1, 1, 0,
doc: /* Return the tangent of ARG. */)
(Lisp_Object arg)
{
double d = extract_float (arg);
d = tan (d);
return make_float (d);
}
DEFUN ("isnan", Fisnan, Sisnan, 1, 1, 0,
doc: /* Return non-nil if argument X is a NaN. */)
(Lisp_Object x)
{
CHECK_FLOAT (x);
return isnan (XFLOAT_DATA (x)) ? Qt : Qnil;
}
/* Although the substitute does not work on NaNs, it is good enough
for platforms lacking the signbit macro. */
#ifndef signbit
# define signbit(x) ((x) < 0 || (IEEE_FLOATING_POINT && !(x) && 1 / (x) < 0))
#endif
DEFUN ("copysign", Fcopysign, Scopysign, 2, 2, 0,
doc: /* Copy sign of X2 to value of X1, and return the result.
Cause an error if X1 or X2 is not a float. */)
(Lisp_Object x1, Lisp_Object x2)
{
double f1, f2;
CHECK_FLOAT (x1);
CHECK_FLOAT (x2);
f1 = XFLOAT_DATA (x1);
f2 = XFLOAT_DATA (x2);
/* Use signbit instead of copysign, to avoid calling make_float when
the result is X1. */
return signbit (f1) != signbit (f2) ? make_float (-f1) : x1;
}
DEFUN ("frexp", Ffrexp, Sfrexp, 1, 1, 0,
doc: /* Get significand and exponent of a floating point number.
Breaks the floating point number X into its binary significand SGNFCAND
\(a floating point value between 0.5 (included) and 1.0 (excluded))
and an integral exponent EXP for 2, such that:
X = SGNFCAND * 2^EXP
The function returns the cons cell (SGNFCAND . EXP).
If X is zero, both parts (SGNFCAND and EXP) are zero. */)
(Lisp_Object x)
{
double f = extract_float (x);
int exponent;
double sgnfcand = frexp (f, &exponent);
return Fcons (make_float (sgnfcand), make_fixnum (exponent));
}
DEFUN ("ldexp", Fldexp, Sldexp, 2, 2, 0,
doc: /* Return SGNFCAND * 2**EXPONENT, as a floating point number.
EXPONENT must be an integer. */)
(Lisp_Object sgnfcand, Lisp_Object exponent)
{
CHECK_FIXNUM (exponent);
int e = min (max (INT_MIN, XFIXNUM (exponent)), INT_MAX);
return make_float (ldexp (extract_float (sgnfcand), e));
}
DEFUN ("exp", Fexp, Sexp, 1, 1, 0,
doc: /* Return the exponential base e of ARG. */)
(Lisp_Object arg)
{
double d = extract_float (arg);
d = exp (d);
return make_float (d);
}
DEFUN ("expt", Fexpt, Sexpt, 2, 2, 0,
doc: /* Return the exponential ARG1 ** ARG2. */)
(Lisp_Object arg1, Lisp_Object arg2)
{
CHECK_NUMBER (arg1);
CHECK_NUMBER (arg2);
/* Common Lisp spec: don't promote if both are integers, and if the
result is not fractional. */
if (INTEGERP (arg1) && !NILP (Fnatnump (arg2)))
return expt_integer (arg1, arg2);
return make_float (pow (XFLOATINT (arg1), XFLOATINT (arg2)));
}
DEFUN ("log", Flog, Slog, 1, 2, 0,
doc: /* Return the natural logarithm of ARG.
If the optional argument BASE is given, return log ARG using that base. */)
(Lisp_Object arg, Lisp_Object base)
{
double d = extract_float (arg);
if (NILP (base))
d = log (d);
else
{
double b = extract_float (base);
if (b == 10.0)
d = log10 (d);
#if HAVE_LOG2
else if (b == 2.0)
d = log2 (d);
#endif
else
d = log (d) / log (b);
}
return make_float (d);
}
DEFUN ("sqrt", Fsqrt, Ssqrt, 1, 1, 0,
doc: /* Return the square root of ARG. */)
(Lisp_Object arg)
{
double d = extract_float (arg);
d = sqrt (d);
return make_float (d);
}
DEFUN ("abs", Fabs, Sabs, 1, 1, 0,
doc: /* Return the absolute value of ARG. */)
(Lisp_Object arg)
{
CHECK_NUMBER (arg);
if (FIXNUMP (arg))
{
if (XFIXNUM (arg) < 0)
arg = make_int (-XFIXNUM (arg));
}
else if (FLOATP (arg))
{
if (signbit (XFLOAT_DATA (arg)))
arg = make_float (- XFLOAT_DATA (arg));
}
else
{
if (mpz_sgn (*xbignum_val (arg)) < 0)
{
mpz_neg (mpz[0], *xbignum_val (arg));
arg = make_integer_mpz ();
}
}
return arg;
}
DEFUN ("float", Ffloat, Sfloat, 1, 1, 0,
doc: /* Return the floating point number equal to ARG. */)
(register Lisp_Object arg)
{
CHECK_NUMBER (arg);
/* If ARG is a float, give 'em the same float back. */
return FLOATP (arg) ? arg : make_float (XFLOATINT (arg));
}
static int
ecount_leading_zeros (EMACS_UINT x)
{
return (EMACS_UINT_WIDTH == UINT_WIDTH ? count_leading_zeros (x)
: EMACS_UINT_WIDTH == ULONG_WIDTH ? count_leading_zeros_l (x)
: count_leading_zeros_ll (x));
}
DEFUN ("logb", Flogb, Slogb, 1, 1, 0,
doc: /* Returns largest integer <= the base 2 log of the magnitude of ARG.
This is the same as the exponent of a float. */)
(Lisp_Object arg)
{
EMACS_INT value;
CHECK_NUMBER (arg);
if (FLOATP (arg))
{
double f = XFLOAT_DATA (arg);
if (f == 0)
return make_float (-HUGE_VAL);
if (!isfinite (f))
return f < 0 ? make_float (-f) : arg;
int ivalue;
frexp (f, &ivalue);
value = ivalue - 1;
}
else if (!FIXNUMP (arg))
value = mpz_sizeinbase (*xbignum_val (arg), 2) - 1;
else
{
EMACS_INT i = XFIXNUM (arg);
if (i == 0)
return make_float (-HUGE_VAL);
value = EMACS_UINT_WIDTH - 1 - ecount_leading_zeros (eabs (i));
}
return make_fixnum (value);
}
/* Return the integer exponent E such that D * FLT_RADIX**E (i.e.,
scalbn (D, E)) is an integer that has precision equal to D and is
representable as a double.
Return DBL_MANT_DIG - DBL_MIN_EXP (the maximum possible valid
scale) if D is zero or tiny. Return one greater than that if
D is infinite, and two greater than that if D is a NaN. */
int
double_integer_scale (double d)
{
int exponent = ilogb (d);
#ifdef HAIKU
/* On Haiku, the values returned by ilogb are nonsensical when
confronted with tiny numbers, inf, or NaN, which breaks the trick
used by code on other platforms, so we have to test for each case
manually, and return the appropriate value. */
if (exponent == FP_ILOGB0)
{
if (isnan (d))
return (DBL_MANT_DIG - DBL_MIN_EXP) + 2;
if (isinf (d))
return (DBL_MANT_DIG - DBL_MIN_EXP) + 1;
return (DBL_MANT_DIG - DBL_MIN_EXP);
}
#endif
return (DBL_MIN_EXP - 1 <= exponent && exponent < INT_MAX
? DBL_MANT_DIG - 1 - exponent
: (DBL_MANT_DIG - DBL_MIN_EXP
+ (isnan (d) ? 2 : exponent == INT_MAX)));
}
/* Convert the Lisp number N to an integer and return a pointer to the
converted integer, represented as an mpz_t *. Use *T as a
temporary; the returned value might be T. Scale N by the maximum
of NSCALE and DSCALE while converting. If NSCALE is nonzero, N
must be a float; signal an overflow if NSCALE is greater than
DBL_MANT_DIG - DBL_MIN_EXP, otherwise scalbn (XFLOAT_DATA (N), NSCALE)
must return an integer value, without rounding or overflow. */
static mpz_t const *
rescale_for_division (Lisp_Object n, mpz_t *t, int nscale, int dscale)
{
mpz_t const *pn;
if (FLOATP (n))
{
if (DBL_MANT_DIG - DBL_MIN_EXP < nscale)
overflow_error ();
mpz_set_d (*t, scalbn (XFLOAT_DATA (n), nscale));
pn = t;
}
else
pn = bignum_integer (t, n);
if (nscale < dscale)
{
emacs_mpz_mul_2exp (*t, *pn, (dscale - nscale) * LOG2_FLT_RADIX);
pn = t;
}
return pn;
}
/* the rounding functions */
static Lisp_Object
rounding_driver (Lisp_Object n, Lisp_Object d,
double (*double_round) (double),
void (*int_divide) (mpz_t, mpz_t const, mpz_t const),
EMACS_INT (*fixnum_divide) (EMACS_INT, EMACS_INT))
{
CHECK_NUMBER (n);
if (NILP (d))
return FLOATP (n) ? double_to_integer (double_round (XFLOAT_DATA (n))) : n;
CHECK_NUMBER (d);
int dscale = 0;
if (FIXNUMP (d))
{
if (XFIXNUM (d) == 0)
xsignal0 (Qarith_error);
/* Divide fixnum by fixnum specially, for speed. */
if (FIXNUMP (n))
return make_int (fixnum_divide (XFIXNUM (n), XFIXNUM (d)));
}
else if (FLOATP (d))
{
if (XFLOAT_DATA (d) == 0)
xsignal0 (Qarith_error);
dscale = double_integer_scale (XFLOAT_DATA (d));
}
int nscale = FLOATP (n) ? double_integer_scale (XFLOAT_DATA (n)) : 0;
/* If the numerator is finite and the denominator infinite, the
quotient is zero and there is no need to try the impossible task
of rescaling the denominator. */
if (dscale == DBL_MANT_DIG - DBL_MIN_EXP + 1 && nscale < dscale)
return make_fixnum (0);
int_divide (mpz[0],
*rescale_for_division (n, &mpz[0], nscale, dscale),
*rescale_for_division (d, &mpz[1], dscale, nscale));
return make_integer_mpz ();
}
static EMACS_INT
ceiling2 (EMACS_INT n, EMACS_INT d)
{
return n / d + ((n % d != 0) & ((n < 0) == (d < 0)));
}
static EMACS_INT
floor2 (EMACS_INT n, EMACS_INT d)
{
return n / d - ((n % d != 0) & ((n < 0) != (d < 0)));
}
static EMACS_INT
truncate2 (EMACS_INT n, EMACS_INT d)
{
return n / d;
}
static EMACS_INT
round2 (EMACS_INT n, EMACS_INT d)
{
/* The C language's division operator gives us the remainder R
corresponding to truncated division, but we want the remainder R1
on the other side of 0 if R1 is closer to 0 than R is; because we
want to round to even, we also want R1 if R and R1 are the same
distance from 0 and if the truncated quotient is odd. */
EMACS_INT q = n / d;
EMACS_INT r = n % d;
bool neg_d = d < 0;
bool neg_r = r < 0;
EMACS_INT abs_r = eabs (r);
EMACS_INT abs_r1 = eabs (d) - abs_r;
if (abs_r1 < abs_r + (q & 1))
q += neg_d == neg_r ? 1 : -1;
return q;
}
static void
rounddiv_q (mpz_t q, mpz_t const n, mpz_t const d)
{
/* Mimic the source code of round2, using mpz_t instead of EMACS_INT. */
mpz_t *r = &mpz[2], *abs_r = r, *abs_r1 = &mpz[3];
mpz_tdiv_qr (q, *r, n, d);
bool neg_d = mpz_sgn (d) < 0;
bool neg_r = mpz_sgn (*r) < 0;
mpz_abs (*abs_r, *r);
mpz_abs (*abs_r1, d);
mpz_sub (*abs_r1, *abs_r1, *abs_r);
if (mpz_cmp (*abs_r1, *abs_r) < (mpz_odd_p (q) != 0))
(neg_d == neg_r ? mpz_add_ui : mpz_sub_ui) (q, q, 1);
}
/* The code uses emacs_rint, so that it works to undefine HAVE_RINT
if `rint' exists but does not work right. */
#ifdef HAVE_RINT
#define emacs_rint rint
#else
static double
emacs_rint (double d)
{
double d1 = d + 0.5;
double r = floor (d1);
return r - (r == d1 && fmod (r, 2) != 0);
}
#endif
#ifndef HAVE_TRUNC
double
trunc (double d)
{
return (d < 0 ? ceil : floor) (d);
}
#endif
DEFUN ("ceiling", Fceiling, Sceiling, 1, 2, 0,
doc: /* Return the smallest integer no less than ARG.
This rounds the value towards +inf.
With optional DIVISOR, return the smallest integer no less than ARG/DIVISOR. */)
(Lisp_Object arg, Lisp_Object divisor)
{
return rounding_driver (arg, divisor, ceil, mpz_cdiv_q, ceiling2);
}
DEFUN ("floor", Ffloor, Sfloor, 1, 2, 0,
doc: /* Return the largest integer no greater than ARG.
This rounds the value towards -inf.
With optional DIVISOR, return the largest integer no greater than ARG/DIVISOR. */)
(Lisp_Object arg, Lisp_Object divisor)
{
return rounding_driver (arg, divisor, floor, mpz_fdiv_q, floor2);
}
DEFUN ("round", Fround, Sround, 1, 2, 0,
doc: /* Return the nearest integer to ARG.
With optional DIVISOR, return the nearest integer to ARG/DIVISOR.
Rounding a value equidistant between two integers may choose the
integer closer to zero, or it may prefer an even integer, depending on
your machine. For example, (round 2.5) can return 3 on some
systems, but 2 on others. */)
(Lisp_Object arg, Lisp_Object divisor)
{
return rounding_driver (arg, divisor, emacs_rint, rounddiv_q, round2);
}
/* Since rounding_driver truncates anyway, no need to call 'trunc'. */
static double
identity (double x)
{
return x;
}
DEFUN ("truncate", Ftruncate, Struncate, 1, 2, 0,
doc: /* Truncate a floating point number to an int.
Rounds ARG toward zero.
With optional DIVISOR, truncate ARG/DIVISOR. */)
(Lisp_Object arg, Lisp_Object divisor)
{
return rounding_driver (arg, divisor, identity, mpz_tdiv_q, truncate2);
}
Lisp_Object
fmod_float (Lisp_Object x, Lisp_Object y)
{
double f1 = XFLOATINT (x);
double f2 = XFLOATINT (y);
f1 = fmod (f1, f2);
/* If the "remainder" comes out with the wrong sign, fix it. */
if (f2 < 0 ? f1 > 0 : f1 < 0)
f1 += f2;
return make_float (f1);
}
DEFUN ("fceiling", Ffceiling, Sfceiling, 1, 1, 0,
doc: /* Return the smallest integer no less than ARG, as a float.
\(Round toward +inf.) */)
(Lisp_Object arg)
{
CHECK_FLOAT (arg);
double d = XFLOAT_DATA (arg);
d = ceil (d);
return make_float (d);
}
DEFUN ("ffloor", Fffloor, Sffloor, 1, 1, 0,
doc: /* Return the largest integer no greater than ARG, as a float.
\(Round toward -inf.) */)
(Lisp_Object arg)
{
CHECK_FLOAT (arg);
double d = XFLOAT_DATA (arg);
d = floor (d);
return make_float (d);
}
DEFUN ("fround", Ffround, Sfround, 1, 1, 0,
doc: /* Return the nearest integer to ARG, as a float. */)
(Lisp_Object arg)
{
CHECK_FLOAT (arg);
double d = XFLOAT_DATA (arg);
d = emacs_rint (d);
return make_float (d);
}
DEFUN ("ftruncate", Fftruncate, Sftruncate, 1, 1, 0,
doc: /* Truncate a floating point number to an integral float value.
\(Round toward zero.) */)
(Lisp_Object arg)
{
CHECK_FLOAT (arg);
double d = XFLOAT_DATA (arg);
d = trunc (d);
return make_float (d);
}
void
syms_of_floatfns (void)
{
defsubr (&Sacos);
defsubr (&Sasin);
defsubr (&Satan);
defsubr (&Scos);
defsubr (&Ssin);
defsubr (&Stan);
defsubr (&Sisnan);
defsubr (&Scopysign);
defsubr (&Sfrexp);
defsubr (&Sldexp);
defsubr (&Sfceiling);
defsubr (&Sffloor);
defsubr (&Sfround);
defsubr (&Sftruncate);
defsubr (&Sexp);
defsubr (&Sexpt);
defsubr (&Slog);
defsubr (&Ssqrt);
defsubr (&Sabs);
defsubr (&Sfloat);
defsubr (&Slogb);
defsubr (&Sceiling);
defsubr (&Sfloor);
defsubr (&Sround);
defsubr (&Struncate);
}