view src/number.c @ 5127:a9c41067dd88 ben-lisp-object

more cleanups, terminology clarification, lots of doc work -------------------- ChangeLog entries follow: -------------------- man/ChangeLog addition: 2010-03-05 Ben Wing <ben@xemacs.org> * internals/internals.texi (Introduction to Allocation): * internals/internals.texi (Integers and Characters): * internals/internals.texi (Allocation from Frob Blocks): * internals/internals.texi (lrecords): * internals/internals.texi (Low-level allocation): Rewrite section on allocation of Lisp objects to reflect the new reality. Remove references to nonexistent XSETINT and XSETCHAR. modules/ChangeLog addition: 2010-03-05 Ben Wing <ben@xemacs.org> * postgresql/postgresql.c (allocate_pgconn): * postgresql/postgresql.c (allocate_pgresult): * postgresql/postgresql.h (struct Lisp_PGconn): * postgresql/postgresql.h (struct Lisp_PGresult): * ldap/eldap.c (allocate_ldap): * ldap/eldap.h (struct Lisp_LDAP): Same changes as in src/ dir. See large log there in ChangeLog, but basically: ALLOC_LISP_OBJECT -> ALLOC_NORMAL_LISP_OBJECT LISP_OBJECT_HEADER -> NORMAL_LISP_OBJECT_HEADER ../hlo/src/ChangeLog addition: 2010-03-05 Ben Wing <ben@xemacs.org> * alloc.c: * alloc.c (old_alloc_sized_lcrecord): * alloc.c (very_old_free_lcrecord): * alloc.c (copy_lisp_object): * alloc.c (zero_sized_lisp_object): * alloc.c (zero_nonsized_lisp_object): * alloc.c (lisp_object_storage_size): * alloc.c (free_normal_lisp_object): * alloc.c (FREE_FIXED_TYPE_WHEN_NOT_IN_GC): * alloc.c (ALLOC_FROB_BLOCK_LISP_OBJECT): * alloc.c (Fcons): * alloc.c (noseeum_cons): * alloc.c (make_float): * alloc.c (make_bignum): * alloc.c (make_bignum_bg): * alloc.c (make_ratio): * alloc.c (make_ratio_bg): * alloc.c (make_ratio_rt): * alloc.c (make_bigfloat): * alloc.c (make_bigfloat_bf): * alloc.c (size_vector): * alloc.c (make_compiled_function): * alloc.c (Fmake_symbol): * alloc.c (allocate_extent): * alloc.c (allocate_event): * alloc.c (make_key_data): * alloc.c (make_button_data): * alloc.c (make_motion_data): * alloc.c (make_process_data): * alloc.c (make_timeout_data): * alloc.c (make_magic_data): * alloc.c (make_magic_eval_data): * alloc.c (make_eval_data): * alloc.c (make_misc_user_data): * alloc.c (Fmake_marker): * alloc.c (noseeum_make_marker): * alloc.c (size_string_direct_data): * alloc.c (make_uninit_string): * alloc.c (make_string_nocopy): * alloc.c (mark_lcrecord_list): * alloc.c (alloc_managed_lcrecord): * alloc.c (free_managed_lcrecord): * alloc.c (sweep_lcrecords_1): * alloc.c (malloced_storage_size): * buffer.c (allocate_buffer): * buffer.c (compute_buffer_usage): * buffer.c (DEFVAR_BUFFER_LOCAL_1): * buffer.c (nuke_all_buffer_slots): * buffer.c (common_init_complex_vars_of_buffer): * buffer.h (struct buffer_text): * buffer.h (struct buffer): * bytecode.c: * bytecode.c (make_compiled_function_args): * bytecode.c (size_compiled_function_args): * bytecode.h (struct compiled_function_args): * casetab.c (allocate_case_table): * casetab.h (struct Lisp_Case_Table): * charset.h (struct Lisp_Charset): * chartab.c (fill_char_table): * chartab.c (Fmake_char_table): * chartab.c (make_char_table_entry): * chartab.c (copy_char_table_entry): * chartab.c (Fcopy_char_table): * chartab.c (put_char_table): * chartab.h (struct Lisp_Char_Table_Entry): * chartab.h (struct Lisp_Char_Table): * console-gtk-impl.h (struct gtk_device): * console-gtk-impl.h (struct gtk_frame): * console-impl.h (struct console): * console-msw-impl.h (struct Lisp_Devmode): * console-msw-impl.h (struct mswindows_device): * console-msw-impl.h (struct msprinter_device): * console-msw-impl.h (struct mswindows_frame): * console-msw-impl.h (struct mswindows_dialog_id): * console-stream-impl.h (struct stream_console): * console-stream.c (stream_init_console): * console-tty-impl.h (struct tty_console): * console-tty-impl.h (struct tty_device): * console-tty.c (allocate_tty_console_struct): * console-x-impl.h (struct x_device): * console-x-impl.h (struct x_frame): * console.c (allocate_console): * console.c (nuke_all_console_slots): * console.c (DEFVAR_CONSOLE_LOCAL_1): * console.c (common_init_complex_vars_of_console): * data.c (make_weak_list): * data.c (make_weak_box): * data.c (make_ephemeron): * database.c: * database.c (struct Lisp_Database): * database.c (allocate_database): * database.c (finalize_database): * device-gtk.c (allocate_gtk_device_struct): * device-impl.h (struct device): * device-msw.c: * device-msw.c (mswindows_init_device): * device-msw.c (msprinter_init_device): * device-msw.c (finalize_devmode): * device-msw.c (allocate_devmode): * device-tty.c (allocate_tty_device_struct): * device-x.c (allocate_x_device_struct): * device.c: * device.c (nuke_all_device_slots): * device.c (allocate_device): * dialog-msw.c (handle_question_dialog_box): * elhash.c: * elhash.c (struct Lisp_Hash_Table): * elhash.c (finalize_hash_table): * elhash.c (make_general_lisp_hash_table): * elhash.c (Fcopy_hash_table): * elhash.h (htentry): * emacs.c (main_1): * eval.c: * eval.c (size_multiple_value): * event-stream.c (finalize_command_builder): * event-stream.c (allocate_command_builder): * event-stream.c (free_command_builder): * event-stream.c (event_stream_generate_wakeup): * event-stream.c (event_stream_resignal_wakeup): * event-stream.c (event_stream_disable_wakeup): * event-stream.c (event_stream_wakeup_pending_p): * events.h (struct Lisp_Timeout): * events.h (struct command_builder): * extents-impl.h: * extents-impl.h (struct extent_auxiliary): * extents-impl.h (struct extent_info): * extents-impl.h (set_extent_no_chase_aux_field): * extents-impl.h (set_extent_no_chase_normal_field): * extents.c: * extents.c (gap_array_marker): * extents.c (gap_array): * extents.c (extent_list_marker): * extents.c (extent_list): * extents.c (stack_of_extents): * extents.c (gap_array_make_marker): * extents.c (extent_list_make_marker): * extents.c (allocate_extent_list): * extents.c (SLOT): * extents.c (mark_extent_auxiliary): * extents.c (allocate_extent_auxiliary): * extents.c (attach_extent_auxiliary): * extents.c (size_gap_array): * extents.c (finalize_extent_info): * extents.c (allocate_extent_info): * extents.c (uninit_buffer_extents): * extents.c (allocate_soe): * extents.c (copy_extent): * extents.c (vars_of_extents): * extents.h: * faces.c (allocate_face): * faces.h (struct Lisp_Face): * faces.h (struct face_cachel): * file-coding.c: * file-coding.c (finalize_coding_system): * file-coding.c (sizeof_coding_system): * file-coding.c (Fcopy_coding_system): * file-coding.h (struct Lisp_Coding_System): * file-coding.h (MARKED_SLOT): * fns.c (size_bit_vector): * font-mgr.c: * font-mgr.c (finalize_fc_pattern): * font-mgr.c (print_fc_pattern): * font-mgr.c (Ffc_pattern_p): * font-mgr.c (Ffc_pattern_create): * font-mgr.c (Ffc_name_parse): * font-mgr.c (Ffc_name_unparse): * font-mgr.c (Ffc_pattern_duplicate): * font-mgr.c (Ffc_pattern_add): * font-mgr.c (Ffc_pattern_del): * font-mgr.c (Ffc_pattern_get): * font-mgr.c (fc_config_create_using): * font-mgr.c (fc_strlist_to_lisp_using): * font-mgr.c (fontset_to_list): * font-mgr.c (Ffc_config_p): * font-mgr.c (Ffc_config_up_to_date): * font-mgr.c (Ffc_config_build_fonts): * font-mgr.c (Ffc_config_get_cache): * font-mgr.c (Ffc_config_get_fonts): * font-mgr.c (Ffc_config_set_current): * font-mgr.c (Ffc_config_get_blanks): * font-mgr.c (Ffc_config_get_rescan_interval): * font-mgr.c (Ffc_config_set_rescan_interval): * font-mgr.c (Ffc_config_app_font_add_file): * font-mgr.c (Ffc_config_app_font_add_dir): * font-mgr.c (Ffc_config_app_font_clear): * font-mgr.c (size): * font-mgr.c (Ffc_config_substitute): * font-mgr.c (Ffc_font_render_prepare): * font-mgr.c (Ffc_font_match): * font-mgr.c (Ffc_font_sort): * font-mgr.c (finalize_fc_config): * font-mgr.c (print_fc_config): * font-mgr.h: * font-mgr.h (struct fc_pattern): * font-mgr.h (XFC_PATTERN): * font-mgr.h (struct fc_config): * font-mgr.h (XFC_CONFIG): * frame-gtk.c (allocate_gtk_frame_struct): * frame-impl.h (struct frame): * frame-msw.c (mswindows_init_frame_1): * frame-x.c (allocate_x_frame_struct): * frame.c (nuke_all_frame_slots): * frame.c (allocate_frame_core): * gc.c: * gc.c (GC_CHECK_NOT_FREE): * glyphs.c (finalize_image_instance): * glyphs.c (allocate_image_instance): * glyphs.c (Fcolorize_image_instance): * glyphs.c (allocate_glyph): * glyphs.c (unmap_subwindow_instance_cache_mapper): * glyphs.c (register_ignored_expose): * glyphs.h (struct Lisp_Image_Instance): * glyphs.h (struct Lisp_Glyph): * glyphs.h (struct glyph_cachel): * glyphs.h (struct expose_ignore): * gui.c (allocate_gui_item): * gui.h (struct Lisp_Gui_Item): * keymap.c (struct Lisp_Keymap): * keymap.c (make_keymap): * lisp.h: * lisp.h (struct Lisp_String_Direct_Data): * lisp.h (struct Lisp_String_Indirect_Data): * lisp.h (struct Lisp_Vector): * lisp.h (struct Lisp_Bit_Vector): * lisp.h (DECLARE_INLINE_LISP_BIT_VECTOR): * lisp.h (struct weak_box): * lisp.h (struct ephemeron): * lisp.h (struct weak_list): * lrecord.h: * lrecord.h (struct lrecord_implementation): * lrecord.h (MC_ALLOC_CALL_FINALIZER): * lrecord.h (struct lcrecord_list): * lstream.c (finalize_lstream): * lstream.c (sizeof_lstream): * lstream.c (Lstream_new): * lstream.c (Lstream_delete): * lstream.h (struct lstream): * marker.c: * marker.c (finalize_marker): * marker.c (compute_buffer_marker_usage): * mule-charset.c: * mule-charset.c (make_charset): * mule-charset.c (compute_charset_usage): * objects-impl.h (struct Lisp_Color_Instance): * objects-impl.h (struct Lisp_Font_Instance): * objects-tty-impl.h (struct tty_color_instance_data): * objects-tty-impl.h (struct tty_font_instance_data): * objects-tty.c (tty_initialize_color_instance): * objects-tty.c (tty_initialize_font_instance): * objects.c (finalize_color_instance): * objects.c (Fmake_color_instance): * objects.c (finalize_font_instance): * objects.c (Fmake_font_instance): * objects.c (reinit_vars_of_objects): * opaque.c: * opaque.c (sizeof_opaque): * opaque.c (make_opaque_ptr): * opaque.c (free_opaque_ptr): * opaque.h: * opaque.h (Lisp_Opaque): * opaque.h (Lisp_Opaque_Ptr): * print.c (printing_unreadable_lcrecord): * print.c (external_object_printer): * print.c (debug_p4): * process.c (finalize_process): * process.c (make_process_internal): * procimpl.h (struct Lisp_Process): * rangetab.c (Fmake_range_table): * rangetab.c (Fcopy_range_table): * rangetab.h (struct Lisp_Range_Table): * scrollbar.c: * scrollbar.c (create_scrollbar_instance): * scrollbar.c (compute_scrollbar_instance_usage): * scrollbar.h (struct scrollbar_instance): * specifier.c (finalize_specifier): * specifier.c (sizeof_specifier): * specifier.c (set_specifier_caching): * specifier.h (struct Lisp_Specifier): * specifier.h (struct specifier_caching): * symeval.h: * symeval.h (SYMBOL_VALUE_MAGIC_P): * symeval.h (DEFVAR_SYMVAL_FWD): * symsinit.h: * syntax.c (init_buffer_syntax_cache): * syntax.h (struct syntax_cache): * toolbar.c: * toolbar.c (allocate_toolbar_button): * toolbar.c (update_toolbar_button): * toolbar.h (struct toolbar_button): * tooltalk.c (struct Lisp_Tooltalk_Message): * tooltalk.c (make_tooltalk_message): * tooltalk.c (struct Lisp_Tooltalk_Pattern): * tooltalk.c (make_tooltalk_pattern): * ui-gtk.c: * ui-gtk.c (allocate_ffi_data): * ui-gtk.c (emacs_gtk_object_finalizer): * ui-gtk.c (allocate_emacs_gtk_object_data): * ui-gtk.c (allocate_emacs_gtk_boxed_data): * ui-gtk.h: * window-impl.h (struct window): * window-impl.h (struct window_mirror): * window.c (finalize_window): * window.c (allocate_window): * window.c (new_window_mirror): * window.c (mark_window_as_deleted): * window.c (make_dummy_parent): * window.c (compute_window_mirror_usage): * window.c (compute_window_usage): Overall point of this change and previous ones in this repository: (1) Introduce new, clearer terminology: everything other than int or char is a "record" object, which comes in two types: "normal objects" and "frob-block objects". Fix up all places that referred to frob-block objects as "simple", "basic", etc. (2) Provide an advertised interface for doing operations on Lisp objects, including creating new types, that is clean and consistent in its naming, uses the above-referenced terms and avoids referencing "lrecords", "old lcrecords", etc., which should hide under the surface. (3) Make the size_in_bytes and finalizer methods take a Lisp_Object rather than a void * for consistency with other methods. (4) Separate finalizer method into finalizer and disksaver, so that normal finalize methods don't have to worry about disksaving. Other specifics: (1) Renaming: LISP_OBJECT_HEADER -> NORMAL_LISP_OBJECT_HEADER ALLOC_LISP_OBJECT -> ALLOC_NORMAL_LISP_OBJECT implementation->basic_p -> implementation->frob_block_p ALLOCATE_FIXED_TYPE_AND_SET_IMPL -> ALLOC_FROB_BLOCK_LISP_OBJECT *FCCONFIG*, wrap_fcconfig -> *FC_CONFIG*, wrap_fc_config *FCPATTERN*, wrap_fcpattern -> *FC_PATTERN*, wrap_fc_pattern (the last two changes make the naming of these macros consistent with the naming of all other macros, since the objects are named fc-config and fc-pattern with a hyphen) (2) Lots of documentation fixes in lrecord.h. (3) Eliminate macros for copying, freeing, zeroing objects, getting their storage size. Instead, new functions: zero_sized_lisp_object() zero_nonsized_lisp_object() lisp_object_storage_size() free_normal_lisp_object() (copy_lisp_object() already exists) LISP_OBJECT_FROB_BLOCK_P() (actually a macro) Eliminated: free_lrecord() zero_lrecord() copy_lrecord() copy_sized_lrecord() old_copy_lcrecord() old_copy_sized_lcrecord() old_zero_lcrecord() old_zero_sized_lcrecord() LISP_OBJECT_STORAGE_SIZE() COPY_SIZED_LISP_OBJECT() COPY_SIZED_LCRECORD() COPY_LISP_OBJECT() ZERO_LISP_OBJECT() FREE_LISP_OBJECT() (4) Catch the remaining places where lrecord stuff was used directly and use the advertised interface, e.g. alloc_sized_lrecord() -> ALLOC_SIZED_LISP_OBJECT(). (5) Make certain statically-declared pseudo-objects (buffer_local_flags, console_local_flags) have their lheader initialized correctly, so things like copy_lisp_object() can work on them. Make extent_auxiliary_defaults a proper heap object Vextent_auxiliary_defaults, and make extent auxiliaries dumpable so that this object can be dumped. allocate_extent_auxiliary() now just creates the object, and attach_extent_auxiliary() creates an extent auxiliary and attaches to an extent, like the old allocate_extent_auxiliary(). (6) Create EXTENT_AUXILIARY_SLOTS macro, similar to the foo-slots.h files but in a macro instead of a file. The purpose is to avoid duplication when iterating over all the slots in an extent auxiliary. Use it. (7) In lstream.c, don't zero out object after allocation because allocation routines take care of this. (8) In marker.c, fix a mistake in computing marker overhead. (9) In print.c, clean up printing_unreadable_lcrecord(), external_object_printer() to avoid lots of ifdef NEW_GC's. (10) Separate toolbar-button allocation into a separate allocate_toolbar_button() function for use in the example code in lrecord.h.
author Ben Wing <ben@xemacs.org>
date Fri, 05 Mar 2010 04:08:17 -0600
parents b5df3737028a
children 0dcd22290039
line wrap: on
line source

/* Numeric types for XEmacs.
   Copyright (C) 2004 Jerry James.
   Copyright (C) 2010 Ben Wing.

This file is part of XEmacs.

XEmacs 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 2, or (at your option) any
later version.

XEmacs 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 XEmacs; see the file COPYING.  If not, write to
the Free Software Foundation, Inc., 51 Franklin St - Fifth Floor,
Boston, MA 02111-1301, USA.  */

/* Synched up with: Not in FSF. */

#include <config.h>
#include <limits.h>
#include "lisp.h"

#ifdef HAVE_BIGFLOAT
#define USED_IF_BIGFLOAT(decl) decl
#else
#define USED_IF_BIGFLOAT(decl) UNUSED (decl)
#endif

Lisp_Object Qrationalp, Qfloatingp, Qrealp;
Lisp_Object Vdefault_float_precision;

static Lisp_Object Qunsupported_type;
static Lisp_Object Vbigfloat_max_prec;
static int number_initialized;

#ifdef HAVE_BIGNUM
bignum scratch_bignum, scratch_bignum2;
#endif
#ifdef HAVE_RATIO
ratio scratch_ratio, scratch_ratio2;
#endif
#ifdef HAVE_BIGFLOAT
bigfloat scratch_bigfloat, scratch_bigfloat2;
#endif

/********************************* Bignums **********************************/
#ifdef HAVE_BIGNUM
static void
bignum_print (Lisp_Object obj, Lisp_Object printcharfun,
	      int UNUSED (escapeflag))
{
  Ascbyte *bstr = bignum_to_string (XBIGNUM_DATA (obj), 10);
  write_ascstring (printcharfun, bstr);
  xfree (bstr);
}

#ifdef NEW_GC
static void
bignum_finalize (void *header)
{
  struct Lisp_Bignum *num = (struct Lisp_Bignum *) header;
  /* #### WARNING: It would be better to put some sort of check to make
     sure this doesn't happen more than once, just in case ---
     e.g. checking if it's zero before finalizing and then setting it to
     zero after finalizing. */
  bignum_fini (num->data);
}
#define BIGNUM_FINALIZE bignum_finalize
#else
#define BIGNUM_FINALIZE 0
#endif

static int
bignum_equal (Lisp_Object obj1, Lisp_Object obj2, int UNUSED (depth),
	      int UNUSED (foldcase))
{
  return bignum_eql (XBIGNUM_DATA (obj1), XBIGNUM_DATA (obj2));
}

static Hashcode
bignum_hash (Lisp_Object obj, int UNUSED (depth))
{
  return bignum_hashcode (XBIGNUM_DATA (obj));
}

static void
bignum_convert (const void *object, void **data, Bytecount *size)
{
  CIbyte *bstr = bignum_to_string (*(bignum *)object, 10);
  *data = bstr;
  *size = strlen(bstr)+1;
}

static void
bignum_convfree (const void * UNUSED (object), void *data,
		 Bytecount UNUSED (size))
{
  xfree (data);
}

static void *
bignum_deconvert (void *object, void *data, Bytecount UNUSED (size))
{
  bignum *b = (bignum *) object;
  bignum_init(*b);
  bignum_set_string(*b, (const char *) data, 10);
  return object;
}

static const struct opaque_convert_functions bignum_opc = {
  bignum_convert,
  bignum_convfree,
  bignum_deconvert
};

static const struct memory_description bignum_description[] = {
  { XD_OPAQUE_DATA_CONVERTIBLE, offsetof (Lisp_Bignum, data),
    0, { &bignum_opc }, XD_FLAG_NO_KKCC },
  { XD_END }
};

DEFINE_DUMPABLE_FROB_BLOCK_LISP_OBJECT ("bignum", bignum, 0, bignum_print,
					BIGNUM_FINALIZE, bignum_equal,
					bignum_hash, bignum_description,
					Lisp_Bignum);

#endif /* HAVE_BIGNUM */

Lisp_Object Qbignump;

DEFUN ("bignump", Fbignump, 1, 1, 0, /*
Return t if OBJECT is a bignum, nil otherwise.
*/
       (object))
{
  return BIGNUMP (object) ? Qt : Qnil;
}


/********************************** Ratios **********************************/
#ifdef HAVE_RATIO
static void
ratio_print (Lisp_Object obj, Lisp_Object printcharfun,
	     int UNUSED (escapeflag))
{
  CIbyte *rstr = ratio_to_string (XRATIO_DATA (obj), 10);
  write_ascstring (printcharfun, rstr);
  xfree (rstr);
}

#ifdef NEW_GC
static void
ratio_finalize (void *header)
{
  struct Lisp_Ratio *num = (struct Lisp_Ratio *) header;
  /* #### WARNING: It would be better to put some sort of check to make
     sure this doesn't happen more than once, just in case ---
     e.g. checking if it's zero before finalizing and then setting it to
     zero after finalizing. */
  ratio_fini (num->data);
}
#define RATIO_FINALIZE ratio_finalize
#else
#define RATIO_FINALIZE 0
#endif

static int
ratio_equal (Lisp_Object obj1, Lisp_Object obj2, int UNUSED (depth),
	     int UNUSED (foldcase))
{
  return ratio_eql (XRATIO_DATA (obj1), XRATIO_DATA (obj2));
}

static Hashcode
ratio_hash (Lisp_Object obj, int UNUSED (depth))
{
  return ratio_hashcode (XRATIO_DATA (obj));
}

static const struct memory_description ratio_description[] = {
  { XD_OPAQUE_PTR, offsetof (Lisp_Ratio, data) },
  { XD_END }
};

DEFINE_NODUMP_FROB_BLOCK_LISP_OBJECT ("ratio", ratio, 0, ratio_print,
				      RATIO_FINALIZE, ratio_equal, ratio_hash,
				      ratio_description, Lisp_Ratio);

#endif /* HAVE_RATIO */

Lisp_Object Qratiop;

DEFUN ("ratiop", Fratiop, 1, 1, 0, /*
Return t if OBJECT is a ratio, nil otherwise.
*/
       (object))
{
  return RATIOP (object) ? Qt : Qnil;
}


/******************************** Rationals *********************************/
DEFUN ("rationalp", Frationalp, 1, 1, 0, /*
Return t if OBJECT is a rational, nil otherwise.
*/
       (object))
{
  return RATIONALP (object) ? Qt : Qnil;
}

DEFUN ("numerator", Fnumerator, 1, 1, 0, /*
Return the numerator of the canonical form of RATIONAL.
If RATIONAL is an integer, RATIONAL is returned.
*/
       (rational))
{
  CONCHECK_RATIONAL (rational);
#ifdef HAVE_RATIO
  if (RATIOP (rational))
    {
      return
	Fcanonicalize_number (make_bignum_bg (XRATIO_NUMERATOR (rational)));
    }
#endif
  return rational;
}

DEFUN ("denominator", Fdenominator, 1, 1, 0, /*
Return the denominator of the canonical form of RATIONAL.
If RATIONAL is an integer, 1 is returned.
*/
       (rational))
{
  CONCHECK_RATIONAL (rational);
#ifdef HAVE_RATIO
  if (RATIOP (rational))
    {
      return Fcanonicalize_number (make_bignum_bg
				   (XRATIO_DENOMINATOR (rational)));
    }
#endif
  return make_int (1);
}


/******************************** Bigfloats *********************************/
#ifdef HAVE_BIGFLOAT
static void
bigfloat_print (Lisp_Object obj, Lisp_Object printcharfun,
		int UNUSED (escapeflag))
{
  Ascbyte *fstr = bigfloat_to_string (XBIGFLOAT_DATA (obj), 10);
  write_ascstring (printcharfun, fstr);
  xfree (fstr);
}

#ifdef NEW_GC
static void
bigfloat_finalize (void *header)
{
  struct Lisp_Bigfloat *num = (struct Lisp_Bigfloat *) header;
  /* #### WARNING: It would be better to put some sort of check to make
     sure this doesn't happen more than once, just in case ---
     e.g. checking if it's zero before finalizing and then setting it to
     zero after finalizing. */
  bigfloat_fini (num->bf);
}
#define BIGFLOAT_FINALIZE bigfloat_finalize
#else
#define BIGFLOAT_FINALIZE 0
#endif

static int
bigfloat_equal (Lisp_Object obj1, Lisp_Object obj2, int UNUSED (depth),
		int UNUSED (foldcase))
{
  return bigfloat_eql (XBIGFLOAT_DATA (obj1), XBIGFLOAT_DATA (obj2));
}

static Hashcode
bigfloat_hash (Lisp_Object obj, int UNUSED (depth))
{
  return bigfloat_hashcode (XBIGFLOAT_DATA (obj));
}

static const struct memory_description bigfloat_description[] = {
  { XD_OPAQUE_PTR, offsetof (Lisp_Bigfloat, bf) },
  { XD_END }
};

DEFINE_DUMPABLE_FROB_BLOCK_LISP_OBJECT ("bigfloat", bigfloat, 0,
					bigfloat_print, BIGFLOAT_FINALIZE,
					bigfloat_equal, bigfloat_hash,
					bigfloat_description, Lisp_Bigfloat);

#endif /* HAVE_BIGFLOAT */

Lisp_Object Qbigfloatp;

DEFUN ("bigfloatp", Fbigfloatp, 1, 1, 0, /*
Return t if OBJECT is a bigfloat, nil otherwise.
*/
       (object))
{
  return BIGFLOATP (object) ? Qt : Qnil;
}

DEFUN ("bigfloat-get-precision", Fbigfloat_get_precision, 1, 1, 0, /*
Return the precision of bigfloat F as an integer.
*/
       (f))
{
  CHECK_BIGFLOAT (f);
#ifdef HAVE_BIGNUM
  bignum_set_ulong (scratch_bignum, XBIGFLOAT_GET_PREC (f));
  return Fcanonicalize_number (make_bignum_bg (scratch_bignum));
#else
  return make_int ((int) XBIGFLOAT_GET_PREC (f));
#endif
}

DEFUN ("bigfloat-set-precision", Fbigfloat_set_precision, 2, 2, 0, /*
Set the precision of F, a bigfloat, to PRECISION, a nonnegative integer.
The new precision of F is returned.  Note that the return value may differ
from PRECISION if the underlying library is unable to support exactly
PRECISION bits of precision.
*/
       (f, precision))
{
  unsigned long prec;

  CHECK_BIGFLOAT (f);
  if (INTP (precision))
    {
      prec = (XINT (precision) <= 0) ? 1UL : (unsigned long) XINT (precision);
    }
#ifdef HAVE_BIGNUM
  else if (BIGNUMP (precision))
    {
      prec = bignum_fits_ulong_p (XBIGNUM_DATA (precision))
	? bignum_to_ulong (XBIGNUM_DATA (precision))
	: UINT_MAX;
    }
#endif
  else
    {
      dead_wrong_type_argument (Qintegerp, f);
      return Qnil;
    }

  XBIGFLOAT_SET_PREC (f, prec);
  return Fbigfloat_get_precision (f);
}

static int
default_float_precision_changed (Lisp_Object UNUSED (sym), Lisp_Object *val,
				 Lisp_Object UNUSED (in_object),
				 int UNUSED (flags))
{
  unsigned long prec;

  CONCHECK_INTEGER (*val);
#ifdef HAVE_BIGFLOAT
  if (INTP (*val))
    prec = XINT (*val);
  else
    {
      if (!bignum_fits_ulong_p (XBIGNUM_DATA (*val)))
	args_out_of_range_3 (*val, Qzero, Vbigfloat_max_prec);
      prec = bignum_to_ulong (XBIGNUM_DATA (*val));
    }
  if (prec != 0UL)
    bigfloat_set_default_prec (prec);
#endif
  return 0;
}


/********************************* Floating *********************************/
Lisp_Object
make_floating (double d)
{
#ifdef HAVE_BIGFLOAT
  if (ZEROP (Vdefault_float_precision))
#endif
    return make_float (d);
#ifdef HAVE_BIGFLOAT
  else
    return make_bigfloat (d, 0UL);
#endif
}

DEFUN ("floatingp", Ffloatingp, 1, 1, 0, /*
Return t if OBJECT is a floating point number of any kind, nil otherwise.
*/
       (object))
{
  return FLOATINGP (object) ? Qt : Qnil;
}


/********************************** Reals ***********************************/
DEFUN ("realp", Frealp, 1, 1, 0, /*
Return t if OBJECT is a real, nil otherwise.
*/
       (object))
{
  return REALP (object) ? Qt : Qnil;
}


/********************************* Numbers **********************************/
DEFUN ("canonicalize-number", Fcanonicalize_number, 1, 1, 0, /*
Return the canonical form of NUMBER.
*/
       (number))
{
  /* The tests should go in order from larger, more expressive, or more
     complex types to smaller, less expressive, or simpler types so that a
     number can cascade all the way down to the simplest type if
     appropriate. */
#ifdef HAVE_RATIO
  if (RATIOP (number) &&
      bignum_fits_long_p (XRATIO_DENOMINATOR (number)) &&
      bignum_to_long (XRATIO_DENOMINATOR (number)) == 1L)
    number = Fcanonicalize_number (make_bignum_bg (XRATIO_NUMERATOR (number)));
#endif
#ifdef HAVE_BIGNUM
  if (BIGNUMP (number) && bignum_fits_emacs_int_p (XBIGNUM_DATA (number)))
    {
      EMACS_INT n = bignum_to_emacs_int (XBIGNUM_DATA (number));
      if (NUMBER_FITS_IN_AN_EMACS_INT (n))
	number = make_int (n);
    }
#endif
  return number;
}

enum number_type
get_number_type (Lisp_Object arg)
{
  if (INTP (arg))
    return FIXNUM_T;
#ifdef HAVE_BIGNUM
  if (BIGNUMP (arg))
    return BIGNUM_T;
#endif
#ifdef HAVE_RATIO
  if (RATIOP (arg))
    return RATIO_T;
#endif
  if (FLOATP (arg))
    return FLOAT_T;
#ifdef HAVE_BIGFLOAT
  if (BIGFLOATP (arg))
    return BIGFLOAT_T;
#endif
  /* Catch unintentional bad uses of this function */
  ABORT ();
  /* NOTREACHED */
  return FIXNUM_T;
}

/* Convert NUMBER to type TYPE.  If TYPE is BIGFLOAT_T then use the indicated
   PRECISION; otherwise, PRECISION is ignored. */
static Lisp_Object
internal_coerce_number (Lisp_Object number, enum number_type type,
#ifdef HAVE_BIGFLOAT
			unsigned long precision
#else
			unsigned long UNUSED (precision)
#endif
			)
{
  enum number_type current_type;

  if (CHARP (number))
    number = make_int (XCHAR (number));
  else if (MARKERP (number))
    number = make_int (marker_position (number));

  /* Note that CHECK_NUMBER ensures that NUMBER is a supported type.  Hence,
     we ABORT() in the #else sections below, because it shouldn't be possible
     to arrive there. */
  CHECK_NUMBER (number);
  current_type = get_number_type (number);
  switch (current_type)
    {
    case FIXNUM_T:
      switch (type)
	{
	case FIXNUM_T:
	  return number;
	case BIGNUM_T:
#ifdef HAVE_BIGNUM
	  return make_bignum (XREALINT (number));
#else
	  ABORT ();
#endif /* HAVE_BIGNUM */
	case RATIO_T:
#ifdef HAVE_RATIO
	  return make_ratio (XREALINT (number), 1UL);
#else
	  ABORT ();
#endif /* HAVE_RATIO */
	case FLOAT_T:
	  return make_float (XREALINT (number));
	case BIGFLOAT_T:
#ifdef HAVE_BIGFLOAT
	  return make_bigfloat (XREALINT (number), precision);
#else
	  ABORT ();
#endif /* HAVE_BIGFLOAT */
	}
    case BIGNUM_T:
#ifdef HAVE_BIGNUM
      switch (type)
	{
	case FIXNUM_T:
	  return make_int (bignum_to_long (XBIGNUM_DATA (number)));
	case BIGNUM_T:
	  return number;
	case RATIO_T:
#ifdef HAVE_RATIO
	  bignum_set_long (scratch_bignum, 1L);
	  return make_ratio_bg (XBIGNUM_DATA (number), scratch_bignum);
#else
	  ABORT ();
#endif /* HAVE_RATIO */
	case FLOAT_T:
	  return make_float (bignum_to_double (XBIGNUM_DATA (number)));
	case BIGFLOAT_T:
#ifdef HAVE_BIGFLOAT
	  {
	    Lisp_Object temp;
	    temp = make_bigfloat (0.0, precision);
	    bigfloat_set_bignum (XBIGFLOAT_DATA (temp), XBIGNUM_DATA (number));
	    return temp;
	  }
#else
	  ABORT ();
#endif /* HAVE_BIGFLOAT */
	}
#else
      ABORT ();
#endif /* HAVE_BIGNUM */
    case RATIO_T:
#ifdef HAVE_RATIO
      switch (type)
	{
	case FIXNUM_T:
	  bignum_div (scratch_bignum, XRATIO_NUMERATOR (number),
		      XRATIO_DENOMINATOR (number));
	  return make_int (bignum_to_long (scratch_bignum));
	case BIGNUM_T:
	  bignum_div (scratch_bignum, XRATIO_NUMERATOR (number),
		      XRATIO_DENOMINATOR (number));
	  return make_bignum_bg (scratch_bignum);
	case RATIO_T:
	  return number;
	case FLOAT_T:
	  return make_float (ratio_to_double (XRATIO_DATA (number)));
	case BIGFLOAT_T:
#ifdef HAVE_BIGFLOAT
	  {
	    Lisp_Object temp;
	    temp = make_bigfloat (0.0, precision);
	    bigfloat_set_ratio (XBIGFLOAT_DATA (temp), XRATIO_DATA (number));
	    return temp;
	  }
#else
	  ABORT ();
#endif /* HAVE_BIGFLOAT */
	}
#else
      ABORT ();
#endif /* HAVE_RATIO */
    case FLOAT_T:
      switch (type)
	{
	case FIXNUM_T:
	  return Ftruncate (number, Qnil);
	case BIGNUM_T:
#ifdef HAVE_BIGNUM
	  bignum_set_double (scratch_bignum, XFLOAT_DATA (number));
	  return make_bignum_bg (scratch_bignum);
#else
	  ABORT ();
#endif /* HAVE_BIGNUM */
	case RATIO_T:
#ifdef HAVE_RATIO
	  ratio_set_double (scratch_ratio, XFLOAT_DATA (number));
	  return make_ratio_rt (scratch_ratio);
#else
	  ABORT ();
#endif /* HAVE_RATIO */
	case FLOAT_T:
	  return number;
	case BIGFLOAT_T:
#ifdef HAVE_BIGFLOAT
	  bigfloat_set_prec (scratch_bigfloat, precision);
	  bigfloat_set_double (scratch_bigfloat, XFLOAT_DATA (number));
	  return make_bigfloat_bf (scratch_bigfloat);
#else
	  ABORT ();
#endif /* HAVE_BIGFLOAT */
	}
    case BIGFLOAT_T:
#ifdef HAVE_BIGFLOAT
      switch (type)
	{
	case FIXNUM_T:
	  return make_int (bigfloat_to_long (XBIGFLOAT_DATA (number)));
	case BIGNUM_T:
#ifdef HAVE_BIGNUM
	  bignum_set_bigfloat (scratch_bignum, XBIGFLOAT_DATA (number));
	  return make_bignum_bg (scratch_bignum);
#else
	  ABORT ();
#endif /* HAVE_BIGNUM */
	case RATIO_T:
#ifdef HAVE_RATIO
	  ratio_set_bigfloat (scratch_ratio, XBIGFLOAT_DATA (number));
	  return make_ratio_rt (scratch_ratio);
#else
	  ABORT ();
#endif
	case FLOAT_T:
	  return make_float (bigfloat_to_double (XBIGFLOAT_DATA (number)));
	case BIGFLOAT_T:
	  /* FIXME: Do we need to change the precision? */
	  return number;
	}
#else
      ABORT ();
#endif /* HAVE_BIGFLOAT */
    }
  ABORT ();
  /* NOTREACHED */
  return Qzero;
}

/* This function promotes its arguments as necessary to make them both the
   same type.  It destructively modifies its arguments to do so.  Characters
   and markers are ALWAYS converted to integers. */
enum number_type
promote_args (Lisp_Object *arg1, Lisp_Object *arg2)
{
  enum number_type type1, type2;

  if (CHARP (*arg1))
    *arg1 = make_int (XCHAR (*arg1));
  else if (MARKERP (*arg1))
    *arg1 = make_int (marker_position (*arg1));
  if (CHARP (*arg2))
    *arg2 = make_int (XCHAR (*arg2));
  else if (MARKERP (*arg2))
    *arg2 = make_int (marker_position (*arg2));

  CHECK_NUMBER (*arg1);
  CHECK_NUMBER (*arg2);

  type1 = get_number_type (*arg1);
  type2 = get_number_type (*arg2);

  if (type1 < type2)
    {
      *arg1 = internal_coerce_number (*arg1, type2,
#ifdef HAVE_BIGFLOAT
				      type2 == BIGFLOAT_T
				      ? XBIGFLOAT_GET_PREC (*arg2) :
#endif
				      0UL);
      return type2;
    }

  if (type2 < type1)
    {
      *arg2 = internal_coerce_number (*arg2, type1,
#ifdef HAVE_BIGFLOAT
				      type1 == BIGFLOAT_T
				      ? XBIGFLOAT_GET_PREC (*arg1) :
#endif
				      0UL);
      return type1;
    }

  /* No conversion necessary */
  return type1;
}

DEFUN ("coerce-number", Fcoerce_number, 2, 3, 0, /*
Convert NUMBER to the indicated type, possibly losing information.
Do not call this function.  Use `coerce' instead.

TYPE is one of the symbols `fixnum', `integer', `ratio', `float', or
`bigfloat'.  Not all of these types may be supported.

PRECISION is the number of bits of precision to use when converting to
bigfloat; it is ignored otherwise.  If nil, the default precision is used.

Note that some conversions lose information.  No error is signaled in such
cases; the information is silently lost.
*/
       (number, type, USED_IF_BIGFLOAT (precision)))
{
  CHECK_SYMBOL (type);
  if (EQ (type, Qfixnum))
    return internal_coerce_number (number, FIXNUM_T, 0UL);
  else if (EQ (type, Qinteger))
    {
      /* If bignums are available, we always convert to one first, then
	 downgrade to a fixnum if possible. */
#ifdef HAVE_BIGNUM
      return Fcanonicalize_number
	(internal_coerce_number (number, BIGNUM_T, 0UL));
#else
      return internal_coerce_number (number, FIXNUM_T, 0UL);
#endif
    }
#ifdef HAVE_RATIO
  else if (EQ (type, Qratio))
    return internal_coerce_number (number, RATIO_T, 0UL);
#endif
  else if (EQ (type, Qfloat))
    return internal_coerce_number (number, FLOAT_T, 0UL);
#ifdef HAVE_BIGFLOAT
  else if (EQ (type, Qbigfloat))
    {
      unsigned long prec;

      if (NILP (precision))
	prec = bigfloat_get_default_prec ();
      else
	{
	  CHECK_INTEGER (precision);
#ifdef HAVE_BIGNUM
	  if (INTP (precision))
#endif /* HAVE_BIGNUM */
	    prec = (unsigned long) XREALINT (precision);
#ifdef HAVE_BIGNUM
	  else
	    {
	      if (!bignum_fits_ulong_p (XBIGNUM_DATA (precision)))
		args_out_of_range (precision, Vbigfloat_max_prec);
	      prec = bignum_to_ulong (XBIGNUM_DATA (precision));
	    }
#endif /* HAVE_BIGNUM */
	}
      return internal_coerce_number (number, BIGFLOAT_T, prec);
    }
#endif /* HAVE_BIGFLOAT */

  Fsignal (Qunsupported_type, type);
  /* NOTREACHED */
  return Qnil;
}


void
syms_of_number (void)
{
#ifdef HAVE_BIGNUM
  INIT_LISP_OBJECT (bignum);
#endif
#ifdef HAVE_RATIO
  INIT_LISP_OBJECT (ratio);
#endif
#ifdef HAVE_BIGFLOAT
  INIT_LISP_OBJECT (bigfloat);
#endif

  /* Type predicates */
  DEFSYMBOL (Qrationalp);
  DEFSYMBOL (Qfloatingp);
  DEFSYMBOL (Qrealp);
  DEFSYMBOL (Qbignump);
  DEFSYMBOL (Qratiop);
  DEFSYMBOL (Qbigfloatp);

  /* Functions */
  DEFSUBR (Fbignump);
  DEFSUBR (Fratiop);
  DEFSUBR (Frationalp);
  DEFSUBR (Fnumerator);
  DEFSUBR (Fdenominator);
  DEFSUBR (Fbigfloatp);
  DEFSUBR (Fbigfloat_get_precision);
  DEFSUBR (Fbigfloat_set_precision);
  DEFSUBR (Ffloatingp);
  DEFSUBR (Frealp);
  DEFSUBR (Fcanonicalize_number);
  DEFSUBR (Fcoerce_number);

  /* Errors */
  DEFERROR_STANDARD (Qunsupported_type, Qwrong_type_argument);
}

void
vars_of_number (void)
{
  /* These variables are Lisp variables rather than number variables so that
     we can put bignums in them. */
  DEFVAR_LISP_MAGIC ("default-float-precision", &Vdefault_float_precision, /*
The default floating-point precision for newly created floating point values.
This should be 0 to create Lisp float types, or an unsigned integer no greater
than `bigfloat-maximum-precision' to create Lisp bigfloat types with the
indicated precision.
*/ default_float_precision_changed);
  Vdefault_float_precision = make_int (0);

  DEFVAR_CONST_LISP ("bigfloat-maximum-precision", &Vbigfloat_max_prec /*
The maximum number of bits of precision a bigfloat can have.
This is determined by the underlying library used to implement bigfloats.
*/);

#ifdef HAVE_BIGFLOAT
  /* Don't create a bignum here.  Otherwise, we lose with NEW_GC + pdump.
     See reinit_vars_of_number(). */
  Vbigfloat_max_prec = make_int (EMACS_INT_MAX);
#else
  Vbigfloat_max_prec = make_int (0);
#endif /* HAVE_BIGFLOAT */

  Fprovide (intern ("number-types"));
#ifdef HAVE_BIGNUM
  Fprovide (intern ("bignum"));
#endif
#ifdef HAVE_RATIO
  Fprovide (intern ("ratio"));
#endif
#ifdef HAVE_BIGFLOAT
  Fprovide (intern ("bigfloat"));
#endif
}

void
reinit_vars_of_number (void)
{
#if defined(HAVE_BIGFLOAT) && defined(HAVE_BIGNUM)
  Vbigfloat_max_prec = make_bignum (0L);
  bignum_set_ulong (XBIGNUM_DATA (Vbigfloat_max_prec), ULONG_MAX);
#endif
}

void
init_number (void)
{
  if (!number_initialized)
    {
      number_initialized = 1;

#ifdef WITH_GMP
      init_number_gmp ();
#endif
#ifdef WITH_MP
      init_number_mp ();
#endif

#ifdef HAVE_BIGNUM
      bignum_init (scratch_bignum);
      bignum_init (scratch_bignum2);
#endif

#ifdef HAVE_RATIO
      ratio_init (scratch_ratio);
      ratio_init (scratch_ratio2);
#endif

#ifdef HAVE_BIGFLOAT
      bigfloat_init (scratch_bigfloat);
      bigfloat_init (scratch_bigfloat2);
#endif

#ifndef PDUMP
      reinit_vars_of_number ();
#endif
    }
}