* allow C-x v i / C-x v v to create a repository if none is available @ 2009-10-08 20:47 Dan Nicolaescu 2009-10-08 21:10 ` Chong Yidong 2009-10-09 19:18 ` Stefan Monnier 0 siblings, 2 replies; 32+ messages in thread From: Dan Nicolaescu @ 2009-10-08 20:47 UTC (permalink / raw) To: emacs-devel When doing C-x v i or C-x v v on an unregistered file that is in a directory not under any version control, the file will be registered with RCS. That is not exactly what most users want. The patch below asks the user what VC backend to use to create a repository, it creates it and registers the file. OK to check in? Index: vc.el =================================================================== RCS file: /cvsroot/emacs/emacs/lisp/vc.el,v retrieving revision 1.732 diff -u -3 -p -u -p -r1.732 vc.el --- vc.el 3 Oct 2009 18:29:26 -0000 1.732 +++ vc.el 8 Oct 2009 20:39:47 -0000 @@ -564,9 +564,6 @@ ;; ;;;; Default Behavior: ;; -;; - do not default to RCS anymore when the current directory is not -;; controlled by any VCS and the user does C-x v v -;; ;; - vc-responsible-backend should not return RCS if no backend ;; declares itself responsible. ;; @@ -842,12 +840,31 @@ be registered." (if (not register) ;; if this is not for registration, the first backend must do (car vc-handled-backends) - ;; for registration, we need to find a new backend that - ;; could register FILE - (dolist (backend vc-handled-backends) - (and (not (vc-call-backend backend 'registered file)) - (vc-call-backend backend 'could-register file) - (throw 'found backend))) + + (if (file-directory-p file) + (let* ((possible-backends + (let (pos) + (dolist (crt vc-handled-backends) + (when (vc-find-backend-function crt 'create-repo) + (push crt pos))) + pos)) + (bk + (intern + (completing-read + (format "%s is not in a version controlled directory.\nWhat VC backend do you want to use to register: " file) + (mapcar 'symbol-name possible-backends) nil t)))) + ;; FIXME: Maybe we need to let bound defauld-directory + ;; around this call to make sure it runs in the right + ;; place? + (vc-call-backend bk 'create-repo) + (throw 'found bk)) + ;; FIXME: Does this case ever happen? + ;; for registration, we need to find a new backend that + ;; could register FILE + (dolist (backend vc-handled-backends) + (and (not (vc-call-backend backend 'registered file)) + (vc-call-backend backend 'could-register file) + (throw 'found backend)))) (error "No backend that could register"))))) (defun vc-expand-dirs (file-or-dir-list) @@ -909,12 +930,12 @@ current buffer." ((and allow-unregistered (not (vc-registered buffer-file-name))) (if state-model-only-files (list (vc-responsible-backend - (file-name-directory (buffer-file-name))) + (file-name-directory (buffer-file-name)) t) (list buffer-file-name) (list buffer-file-name) (when state-model-only-files 'unregistered) nil) (list (vc-responsible-backend - (file-name-directory (buffer-file-name))) + (file-name-directory (buffer-file-name)) t) (list buffer-file-name)))) (t (error "No fileset is available here"))))) ^ permalink raw reply [flat|nested] 32+ messages in thread
* Re: allow C-x v i / C-x v v to create a repository if none is available 2009-10-08 20:47 allow C-x v i / C-x v v to create a repository if none is available Dan Nicolaescu @ 2009-10-08 21:10 ` Chong Yidong 2009-10-09 19:18 ` Stefan Monnier 1 sibling, 0 replies; 32+ messages in thread From: Chong Yidong @ 2009-10-08 21:10 UTC (permalink / raw) To: Dan Nicolaescu; +Cc: emacs-devel Dan Nicolaescu <dann@ics.uci.edu> writes: > (format "%s is not in a version controlled directory.\nWhat VC backend do you want to use to register: " file) A prompt should not be phrased as a question. This needs to be something like "Register using VC backend: " Other than that, I don't see any problems with this change, but wait a few days for others to comment. (This change probably also needs a NEWS entry). ^ permalink raw reply [flat|nested] 32+ messages in thread
* Re: allow C-x v i / C-x v v to create a repository if none is available 2009-10-08 20:47 allow C-x v i / C-x v v to create a repository if none is available Dan Nicolaescu 2009-10-08 21:10 ` Chong Yidong @ 2009-10-09 19:18 ` Stefan Monnier 2009-10-09 19:32 ` Dan Nicolaescu ` (3 more replies) 1 sibling, 4 replies; 32+ messages in thread From: Stefan Monnier @ 2009-10-09 19:18 UTC (permalink / raw) To: Dan Nicolaescu; +Cc: emacs-devel > When doing C-x v i or C-x v v on an unregistered file that is in a > directory not under any version control, the file will be registered > with RCS. That is not exactly what most users want. Very good point. In the past, there wasn't much choice anyway since creating a CVS repository required a lot more work, but indeed, with current DVCS such a behavior makes sense again. Now, most relevant backends will also want to know where you want to put the root of your new repository. Should we let the backend function `create-repo' prompt for this, or should we move it to the generic part of the code? You seem to have taken the first choice, whereas I'd lean towards the second. Stefan ^ permalink raw reply [flat|nested] 32+ messages in thread
* Re: allow C-x v i / C-x v v to create a repository if none is available 2009-10-09 19:18 ` Stefan Monnier @ 2009-10-09 19:32 ` Dan Nicolaescu 2009-10-13 18:40 ` Stefan Monnier 2009-10-13 15:59 ` Dan Nicolaescu ` (2 subsequent siblings) 3 siblings, 1 reply; 32+ messages in thread From: Dan Nicolaescu @ 2009-10-09 19:32 UTC (permalink / raw) To: Stefan Monnier; +Cc: emacs-devel Stefan Monnier <monnier@IRO.UMontreal.CA> writes: > > When doing C-x v i or C-x v v on an unregistered file that is in a > > directory not under any version control, the file will be registered > > with RCS. That is not exactly what most users want. > > Very good point. In the past, there wasn't much choice anyway since > creating a CVS repository required a lot more work, but indeed, with > current DVCS such a behavior makes sense again. > > Now, most relevant backends will also want to know where you want to put > the root of your new repository. Should we let the backend function > `create-repo' prompt for this, or should we move it to the generic part > of the code? You seem to have taken the first choice, whereas I'd lean > towards the second. I just took smallest patch path :-), just create the repository in the current directory. Do we have any backend specific function that are required to prompt? I don't think we do. So I'd say that for consistency it would be better to prompt in the generic code. This also avoid the code duplication in all backends. What's your reasoning for leaning towards the second? ^ permalink raw reply [flat|nested] 32+ messages in thread
* Re: allow C-x v i / C-x v v to create a repository if none is available 2009-10-09 19:32 ` Dan Nicolaescu @ 2009-10-13 18:40 ` Stefan Monnier 0 siblings, 0 replies; 32+ messages in thread From: Stefan Monnier @ 2009-10-13 18:40 UTC (permalink / raw) To: Dan Nicolaescu; +Cc: emacs-devel > Do we have any backend specific function that are required to prompt? > I don't think we do. > So I'd say that for consistency it would be better to prompt in the > generic code. This also avoid the code duplication in all backends. We agree, Stefan ^ permalink raw reply [flat|nested] 32+ messages in thread
* Re: allow C-x v i / C-x v v to create a repository if none is available 2009-10-09 19:18 ` Stefan Monnier 2009-10-09 19:32 ` Dan Nicolaescu @ 2009-10-13 15:59 ` Dan Nicolaescu 2009-10-21 19:06 ` Dan Nicolaescu 2009-10-22 18:56 ` Code for converting between Elisp and Calc floats Jay Belanger 3 siblings, 0 replies; 32+ messages in thread From: Dan Nicolaescu @ 2009-10-13 15:59 UTC (permalink / raw) To: Stefan Monnier; +Cc: emacs-devel Stefan Monnier <monnier@IRO.UMontreal.CA> writes: > > When doing C-x v i or C-x v v on an unregistered file that is in a > > directory not under any version control, the file will be registered > > with RCS. That is not exactly what most users want. > > Very good point. In the past, there wasn't much choice anyway since > creating a CVS repository required a lot more work, but indeed, with > current DVCS such a behavior makes sense again. > > Now, most relevant backends will also want to know where you want to put > the root of your new repository. Should we let the backend function > `create-repo' prompt for this, or should we move it to the generic part > of the code? You seem to have taken the first choice, whereas I'd lean > towards the second. Here's an updated patch. For the reasons that I showed in my previous mail, I'm inclined to the first choice. But if you really feel strongly about this, I can change it. Just outline how you want it done. Index: vc.el =================================================================== RCS file: /cvsroot/emacs/emacs/lisp/vc.el,v retrieving revision 1.732 diff -u -3 -p -u -p -r1.732 vc.el --- vc.el 3 Oct 2009 18:29:26 -0000 1.732 +++ vc.el 13 Oct 2009 15:49:45 -0000 @@ -564,9 +564,6 @@ ;; ;;;; Default Behavior: ;; -;; - do not default to RCS anymore when the current directory is not -;; controlled by any VCS and the user does C-x v v -;; ;; - vc-responsible-backend should not return RCS if no backend ;; declares itself responsible. ;; @@ -634,7 +631,8 @@ (require 'vc-dispatcher) (eval-when-compile - (require 'cl)) + (require 'cl) + (require 'dired)) (unless (assoc 'vc-parent-buffer minor-mode-alist) (setq minor-mode-alist @@ -818,11 +816,14 @@ The optional argument REGISTER means tha registration should be found. If REGISTER is nil, then if FILE is already registered, return the -backend of FILE. If FILE is not registered, or a directory, then the +backend of FILE. If FILE is not registered, then the first backend in `vc-handled-backends' that declares itself responsible for FILE is returned. If no backend declares itself responsible, return the first backend. +If REGISTER is non-nil and FILE is a directory, create a VC +repository that can be used to register FILE. + If REGISTER is non-nil, return the first responsible backend under which FILE is not yet registered. If there is no such backend, return the first backend under which FILE is not yet registered, but could @@ -842,13 +843,47 @@ be registered." (if (not register) ;; if this is not for registration, the first backend must do (car vc-handled-backends) - ;; for registration, we need to find a new backend that - ;; could register FILE - (dolist (backend vc-handled-backends) - (and (not (vc-call-backend backend 'registered file)) - (vc-call-backend backend 'could-register file) - (throw 'found backend))) - (error "No backend that could register"))))) + (if (file-directory-p file) + (let* ((possible-backends + (let (pos) + (dolist (crt vc-handled-backends) + (when (vc-find-backend-function crt 'create-repo) + (push crt pos))) + pos)) + (bk + (intern + ;; Read the VC backend from the user, only + ;; complete with the backends that have the + ;; 'create-repo method. + (completing-read + (format "%s is not in a version controlled directory.\nUse VC backend: " file) + (mapcar 'symbol-name possible-backends) nil t))) + (repo-dir + (file-name-as-directory + (let ((def-dir file)) + ;; read the directory where to create the + ;; repository, make sure it's a parent of + ;; file. + (read-file-name + (format "create %s repository in: " bk) + default-directory nil t nil + (lambda (arg) + (and (file-directory-p arg) + (vc-string-prefix-p (expand-file-name arg) def-dir)))))))) + (let ((default-directory repo-dir)) + (vc-call-backend bk 'create-repo)) + (throw 'found bk)) + + ;; FIXME: this case does not happen with the current code. + ;; Should we keep it? + ;; + ;; For registration, we need to find a new backend that + ;; could register FILE. + (dolist (backend vc-handled-backends) + (and (not (vc-call-backend backend 'registered file)) + (vc-call-backend backend 'could-register file) + (throw 'found backend)))) + (error "no backend that could register"))))) (defun vc-expand-dirs (file-or-dir-list) "Expands directories in a file list specification. @@ -889,6 +924,10 @@ current buffer." (cond ((derived-mode-p 'vc-dir-mode) (vc-dir-deduce-fileset state-model-only-files)) + ((derived-mode-p 'dired-mode) + (if observer + (vc-dired-deduce-fileset) + (error "state changing vc operations not supported in `dired-mode'"))) ((setq backend (vc-backend buffer-file-name)) (if state-model-only-files (list backend (list buffer-file-name) @@ -909,13 +948,13 @@ current buffer." ((and allow-unregistered (not (vc-registered buffer-file-name))) (if state-model-only-files (list (vc-responsible-backend - (file-name-directory (buffer-file-name))) + (file-name-directory (buffer-file-name)) t) (list buffer-file-name) (list buffer-file-name) (when state-model-only-files 'unregistered) nil) (list (vc-responsible-backend - (file-name-directory (buffer-file-name))) + (file-name-directory (buffer-file-name)) t) (list buffer-file-name)))) (t (error "No fileset is available here"))))) ^ permalink raw reply [flat|nested] 32+ messages in thread
* Re: allow C-x v i / C-x v v to create a repository if none is available 2009-10-09 19:18 ` Stefan Monnier 2009-10-09 19:32 ` Dan Nicolaescu 2009-10-13 15:59 ` Dan Nicolaescu @ 2009-10-21 19:06 ` Dan Nicolaescu 2009-10-23 7:45 ` Dan Nicolaescu 2009-10-22 18:56 ` Code for converting between Elisp and Calc floats Jay Belanger 3 siblings, 1 reply; 32+ messages in thread From: Dan Nicolaescu @ 2009-10-21 19:06 UTC (permalink / raw) To: Stefan Monnier; +Cc: emacs-devel Stefan Monnier <monnier@IRO.UMontreal.CA> writes: > > When doing C-x v i or C-x v v on an unregistered file that is in a > > directory not under any version control, the file will be registered > > with RCS. That is not exactly what most users want. > > Very good point. In the past, there wasn't much choice anyway since > creating a CVS repository required a lot more work, but indeed, with > current DVCS such a behavior makes sense again. Unfortunately I had to disable this change, it caused bug#4773. Ideas on how this stuff is supposed to work are very welcome. ^ permalink raw reply [flat|nested] 32+ messages in thread
* Re: allow C-x v i / C-x v v to create a repository if none is available 2009-10-21 19:06 ` Dan Nicolaescu @ 2009-10-23 7:45 ` Dan Nicolaescu 2009-10-23 13:12 ` Stefan Monnier 2009-10-24 2:34 ` Miles Bader 0 siblings, 2 replies; 32+ messages in thread From: Dan Nicolaescu @ 2009-10-23 7:45 UTC (permalink / raw) To: Stefan Monnier; +Cc: emacs-devel Dan Nicolaescu <dann@ics.uci.edu> writes: > Stefan Monnier <monnier@IRO.UMontreal.CA> writes: > > > > When doing C-x v i or C-x v v on an unregistered file that is in a > > > directory not under any version control, the file will be registered > > > with RCS. That is not exactly what most users want. > > > > Very good point. In the past, there wasn't much choice anyway since > > creating a CVS repository required a lot more work, but indeed, with > > current DVCS such a behavior makes sense again. > > Unfortunately I had to disable this change, it caused bug#4773. > Ideas on how this stuff is supposed to work are very welcome. Here's a new version of this. I've never liked the REGISTER argument to vc-responsible-backend, it makes the function have strange behavior, so I separated the REGISTER behavior into a new function: vc-get-backend-for-registration (suggestions for a better name?). IMHO the code and semantics are a lot cleaner now. Then I made vc-responsible-backend throw an error in case no responsible backend is found (instead of just returning the first backend). I removed: (when (not vc-handled-backends))) If that condition is true then there are bigger problems than this. Registering with various backends, and creating repositories work fine. OK to check in? Index: vc.el =================================================================== RCS file: /cvsroot/emacs/emacs/lisp/vc.el,v retrieving revision 1.736 diff -u -3 -p -u -p -r1.736 vc.el --- vc.el 21 Oct 2009 19:03:36 -0000 1.736 +++ vc.el 23 Oct 2009 07:31:21 -0000 @@ -799,80 +800,66 @@ been updated to their corresponding valu ;;; Code for deducing what fileset and backend to assume -(defun vc-responsible-backend (file &optional register) +(defun vc-get-backend-for-registration (file) + "Return a backend that can be used for registering FILE. + +If no backend declares itself responsible for FILE, then FILE +must not be in a version controlled directory, so try to create a +repository, prompting for the directory and the VC backend to +use." + (catch 'found + ;; First try: find a responsible backend, it must be a backend + ;; under which FILE is not yet registered. + (dolist (backend vc-handled-backends) + (and (not (vc-call-backend backend 'registered file)) + (vc-call-backend backend 'responsible-p file) + (throw 'found backend))) + ;; no responsible backend + (let* ((possible-backends + (let (pos) + (dolist (crt vc-handled-backends) + (when (vc-find-backend-function crt 'create-repo) + (push crt pos))) + pos)) + (bk + (intern + ;; Read the VC backend from the user, only + ;; complete with the backends that have the + ;; 'create-repo method. + (completing-read + (format "%s is not in a version controlled directory.\nUse VC backend: " file) + (mapcar 'symbol-name possible-backends) nil t))) + (repo-dir + (let ((def-dir (file-name-directory file))) + ;; read the directory where to create the + ;; repository, make sure it's a parent of + ;; file. + (read-file-name + (format "create %s repository in: " bk) + default-directory def-dir t nil + (lambda (arg) + (message "arg %s" arg) + (and (file-directory-p arg) + (vc-string-prefix-p (expand-file-name arg) def-dir))))))) + (let ((default-directory repo-dir)) + (vc-call-backend bk 'create-repo)) + (throw 'found bk)))) + +(defun vc-responsible-backend (file) "Return the name of a backend system that is responsible for FILE. -The optional argument REGISTER means that a backend suitable for -registration should be found. -If REGISTER is nil, then if FILE is already registered, return the +If FILE is already registered, return the backend of FILE. If FILE is not registered, then the first backend in `vc-handled-backends' that declares itself -responsible for FILE is returned. If no backend declares itself -responsible, return the first backend. - -If REGISTER is non-nil and FILE is a directory, create a VC -repository that can be used to register FILE. - -If REGISTER is non-nil, return the first responsible backend under -which FILE is not yet registered. If there is no such backend, return -the first backend under which FILE is not yet registered, but could -be registered." - (when (not vc-handled-backends) - (error "No handled backends")) - (or (and (not (file-directory-p file)) (not register) (vc-backend file)) +responsible for FILE is returned." + (or (and (not (file-directory-p file)) (vc-backend file)) (catch 'found ;; First try: find a responsible backend. If this is for registration, ;; it must be a backend under which FILE is not yet registered. (dolist (backend vc-handled-backends) - (and (or (not register) - (not (vc-call-backend backend 'registered file))) - (vc-call-backend backend 'responsible-p file) + (and (vc-call-backend backend 'responsible-p file) (throw 'found backend))) - ;; no responsible backend - (if (not register) - ;; if this is not for registration, the first backend must do - (car vc-handled-backends) - (if (file-directory-p file) - (let* ((possible-backends - (let (pos) - (dolist (crt vc-handled-backends) - (when (vc-find-backend-function crt 'create-repo) - (push crt pos))) - pos)) - (bk - (intern - ;; Read the VC backend from the user, only - ;; complete with the backends that have the - ;; 'create-repo method. - (completing-read - (format "%s is not in a version controlled directory.\nUse VC backend: " file) - (mapcar 'symbol-name possible-backends) nil t))) - (repo-dir - (file-name-as-directory - (let ((def-dir file)) - ;; read the directory where to create the - ;; repository, make sure it's a parent of - ;; file. - (read-file-name - (format "create %s repository in: " bk) - default-directory nil t nil - (lambda (arg) - (and (file-directory-p arg) - (vc-string-prefix-p (expand-file-name arg) def-dir)))))))) - (let ((default-directory repo-dir)) - (vc-call-backend bk 'create-repo)) - (throw 'found bk)) - - ;; FIXME: this case does not happen with the current code. - ;; Should we keep it? - ;; - ;; For registration, we need to find a new backend that - ;; could register FILE. - (dolist (backend vc-handled-backends) - (and (not (vc-call-backend backend 'registered file)) - (vc-call-backend backend 'could-register file) - (throw 'found backend)))) - (error "no backend that could register"))))) + (error "No VC backend is responsible for %s" file)))) (defun vc-expand-dirs (file-or-dir-list) "Expands directories in a file list specification. @@ -932,14 +923,12 @@ current buffer." (error "Buffer %s is not associated with a file" (buffer-name))) ((and allow-unregistered (not (vc-registered buffer-file-name))) (if state-model-only-files - (list (vc-responsible-backend - (file-name-directory (buffer-file-name))) + (list (vc-get-backend-for-registration (buffer-file-name)) (list buffer-file-name) (list buffer-file-name) (when state-model-only-files 'unregistered) nil) - (list (vc-responsible-backend - (file-name-directory (buffer-file-name))) + (list (vc-get-backend-for-registration (buffer-file-name)) (list buffer-file-name)))) (t (error "No fileset is available here"))))) ^ permalink raw reply [flat|nested] 32+ messages in thread
* Re: allow C-x v i / C-x v v to create a repository if none is available 2009-10-23 7:45 ` Dan Nicolaescu @ 2009-10-23 13:12 ` Stefan Monnier 2009-10-24 2:34 ` Miles Bader 1 sibling, 0 replies; 32+ messages in thread From: Stefan Monnier @ 2009-10-23 13:12 UTC (permalink / raw) To: Dan Nicolaescu; +Cc: emacs-devel > Here's a new version of this. > I've never liked the REGISTER argument to vc-responsible-backend, it > makes the function have strange behavior, so I separated > the REGISTER behavior into a new function: > vc-get-backend-for-registration (suggestions for a better name?). > IMHO the code and semantics are a lot cleaner now. Looks fine to me, thank you, Stefan ^ permalink raw reply [flat|nested] 32+ messages in thread
* Re: allow C-x v i / C-x v v to create a repository if none is available 2009-10-23 7:45 ` Dan Nicolaescu 2009-10-23 13:12 ` Stefan Monnier @ 2009-10-24 2:34 ` Miles Bader 2009-10-24 6:35 ` Dan Nicolaescu 1 sibling, 1 reply; 32+ messages in thread From: Miles Bader @ 2009-10-24 2:34 UTC (permalink / raw) To: Dan Nicolaescu; +Cc: Stefan Monnier, emacs-devel Dan Nicolaescu <dann@ics.uci.edu> writes: > vc-get-backend-for-registration (suggestions for a better name?). Just one comment: none of the other vc functions use "-get-", so this one probably shouldn't either. So maybe, "vc-backend-for-registration"? -Miles -- Optimist, n. A proponent of the doctrine that black is white. ^ permalink raw reply [flat|nested] 32+ messages in thread
* Re: allow C-x v i / C-x v v to create a repository if none is available 2009-10-24 2:34 ` Miles Bader @ 2009-10-24 6:35 ` Dan Nicolaescu 0 siblings, 0 replies; 32+ messages in thread From: Dan Nicolaescu @ 2009-10-24 6:35 UTC (permalink / raw) To: Miles Bader; +Cc: Stefan Monnier, emacs-devel Miles Bader <miles@gnu.org> writes: > Dan Nicolaescu <dann@ics.uci.edu> writes: > > vc-get-backend-for-registration (suggestions for a better name?). > > Just one comment: none of the other vc functions use "-get-", so this > one probably shouldn't either. So maybe, "vc-backend-for-registration"? Thanks. Done. ^ permalink raw reply [flat|nested] 32+ messages in thread
* Code for converting between Elisp and Calc floats 2009-10-09 19:18 ` Stefan Monnier ` (2 preceding siblings ...) 2009-10-21 19:06 ` Dan Nicolaescu @ 2009-10-22 18:56 ` Jay Belanger 2009-10-22 20:04 ` James Cloos ` (2 more replies) 3 siblings, 3 replies; 32+ messages in thread From: Jay Belanger @ 2009-10-22 18:56 UTC (permalink / raw) To: emacs-devel; +Cc: jay.p.belanger Vincent Belaïche has been working on making Calc more useful as an Emacs library. Among the things he's working on is efficient conversions between Calc floats and Elisp floats. This is best done using some lisp functions that are written in C. Since it's C code, I wanted an okay before I committed it. I have a copy of it at the end of this message. Thanks, Jay /** Code:*/ #include <config.h> #include "lisp.h" #if HAVE_X_WINDOWS #include "xterm.h" #endif #if STDC_HEADERS #include <float.h> #endif /* if HAVE_DOUBLE_SIZEOF is not defined, then try to define it from float.h, when possible, the values in table below are considered. Otherwise you may define it from the make command line if you dare! +--------------------+----------------------------------------+ |HAVE_DOUBLE_SIZEOF |meaning | +--------------------+----------------------------------------+ |0 |binary IEEE754 is not used by Lisp | | |floats, or Lisp floats are not supported| +--------------------+----------------------------------------+ |4 |32bit binary IEEE is used by Lisp floats| | | | +--------------------+----------------------------------------+ |8 |64bit binary IEEE is used by Lisp floats| +--------------------+----------------------------------------+ |10 |79bit binary IEEE is used by Lisp floats| +--------------------+----------------------------------------+ |16 |128bit binary IEEE is used by Lisp | | |floats | +--------------------+----------------------------------------+ */ #ifndef HAVE_DOUBLE_SIZEOF # if !defined LISP_FLOAT_TYPE \ || !defined FLT_RADIX || !defined DBL_MANT_DIG \ || !defined DBL_MIN_EXP || !defined DBL_MAX_EXP \ || FLT_RADIX != 2 # define HAVE_DOUBLE_SIZEOF 0 # elif (DBL_MANT_DIG == 1+23 \ && DBL_MIN_EXP == 1+-126 \ && DBL_MAX_EXP == 1+127) # define HAVE_DOUBLE_SIZEOF 4 # elif (DBL_MANT_DIG == 1+52 \ && DBL_MIN_EXP == 1+-1022 \ && DBL_MAX_EXP == 1+1023) # define HAVE_DOUBLE_SIZEOF 8 # elif (DBL_MANT_DIG == 1+64 \ && DBL_MIN_EXP == 1+-16382 \ && DBL_MAX_EXP == 1+16383) # define HAVE_DOUBLE_SIZEOF 10 # elif (DBL_MANT_DIG == 1+112 \ && DBL_MIN_EXP == 1+-16382 \ && DBL_MAX_EXP == 1+16383) # define HAVE_DOUBLE_SIZEOF 16 # else # define HAVE_DOUBLE_SIZEOF 0 # endif #endif /* end of to be moved to config.h */ /* #########################################################################*/ /* Essential macro definitions for definition of IEEE754 format */ /* =========================================================================*/ #define HAVE_BINARY_IEEE754 1 #ifdef HAVE_DOUBLE_SIZEOF # if HAVE_DOUBLE_SIZEOF == 4 # define IEEE754_EXP_SIZE 8 # define IEEE754_MANT_SIZE 23/* no phantom*/ # elif HAVE_DOUBLE_SIZEOF == 8 # define IEEE754_EXP_SIZE 11 # define IEEE754_MANT_SIZE 52/* no phantom*/ # elif HAVE_DOUBLE_SIZEOF == 10 # define IEEE754_EXP_SIZE 15 # define IEEE754_MANT_SIZE 64/* no phantom*/ # elif HAVE_DOUBLE_SIZEOF == 16 # define IEEE754_EXP_SIZE 15 # define IEEE754_MANT_SIZE 112/* no phantom*/ # else # undef HAVE_BINARY_IEEE754 # endif #else # error incomplete config, missing HAVE_DOUBLE_SIZEOF #endif /* #########################################################################*/ /* Lisp variables support in C */ /* =========================================================================*/ int math_lisp_float_binary_ieee754_conformance; #ifdef HAVE_BINARY_IEEE754 EMACS_INT math_binary_ieee754_float_max_exp, math_binary_ieee754_float_min_exp, math_binary_ieee754_mant_size; #endif /* #########################################################################*/ /* Other macro definitions for handling of IEEE754 binary format */ /* =========================================================================*/ #ifdef HAVE_BINARY_IEEE754 # define MATH_DOUBLE_INT_COUNT ((sizeof(double)+sizeof(unsigned int)-1)/sizeof(unsigned int)) # define MATH_SIGN_POS (IEEE754_EXP_SIZE+IEEE754_MANT_SIZE \ -(MATH_DOUBLE_INT_COUNT-1)*sizeof(unsigned int)*8) # define MATH_EXP_MASK ((1<<IEEE754_EXP_SIZE)-1) # define MATH_EXP_BIAS ((1<<(IEEE754_EXP_SIZE-1))-1) # define MATH_MANT_LIST_SIZE ((IEEE754_MANT_SIZE+1 + VALBITS-2)/(VALBITS-1)) # ifndef WORDS_BIG_ENDIAN /* little endian case */ # define MATH_DOUBLE_INT_LSB 0 # define MATH_DOUBLE_INT_MSB (MATH_DOUBLE_INT_COUNT-1) # define MATH_DOUBLE_INT_INC 1 # else /* big endian case */ # define MATH_DOUBLE_INT_LSB (MATH_DOUBLE_INT_COUNT-1) # define MATH_DOUBLE_INT_MSB 0 # define MATH_DOUBLE_INT_INC -1 # endif typedef union union_double_map_ot { unsigned int m_aui[MATH_DOUBLE_INT_COUNT]; double m_f; } double_map_ot; #endif /* #########################################################################*/ /* Private functions */ /* =========================================================================*/ #ifdef HAVE_BINARY_IEEE754 /* Produce a Not-a-Number. `sign' is the sign bit and shall be either 0 or 1. */ static Lisp_Object math_make_nan(int sign) { double_map_ot double_map_o; int i; for(i = 0; i < MATH_DOUBLE_INT_COUNT; ++i) double_map_o.m_aui[i] = ~0; if(!sign) double_map_o.m_aui[MATH_DOUBLE_INT_MSB] &= ~(1<<MATH_SIGN_POS); return make_float(double_map_o.m_f); } /* fill a float starting from MSB*/ static double math_make_float(int bitfield_count,unsigned int const bit_val_aui[],int const bit_count_ai[]) { double_map_ot double_map_o; int j = 0; int i = MATH_DOUBLE_INT_MSB; unsigned int bit_val; int bit_count; int remain_count; int to_fill; unsigned int word = 0; remain_count = 0; for(j = 0; j < bitfield_count; ++j) remain_count += bit_count_ai[j]; to_fill = MATH_SIGN_POS+1; bit_val = bit_val_aui[j = 0]; bit_count = bit_count_ai[j++]; for(;;) { if(to_fill >= bit_count) { bit_val <<= (to_fill - bit_count); word |= bit_val; remain_count -= bit_count; to_fill -= bit_count; bit_count = 0; } else { word |= bit_val>>(bit_count - to_fill); bit_count -= to_fill; remain_count -= to_fill; /* erase all bits more significant than bit_count in bit_val */ to_fill = sizeof(unsigned int)*8 - bit_count; bit_val <<= to_fill; bit_val >>= to_fill; to_fill = 0; } if(remain_count == 0) goto fill_complete; else if(remain_count < 0) { word <<= -remain_count; goto fill_complete; } else { if(to_fill == 0) { double_map_o.m_aui[i] = word; word = 0; i -= MATH_DOUBLE_INT_INC; to_fill = sizeof(unsigned int)*8; } if(bit_count == 0) { bit_val = bit_val_aui[j]; bit_count = bit_count_ai[j++]; } } } fill_complete: do { double_map_o.m_aui[i] = word; word = 0; } while((i -= MATH_DOUBLE_INT_INC) != (MATH_DOUBLE_INT_LSB-MATH_DOUBLE_INT_INC)); /* printf("math_make_float: %ud %ud\n",double_map_o.m_aui[1],double_map_o.m_aui[0]);*/ return double_map_o.m_f; } /* sign bit shall be 0 or 1 */ static Lisp_Object math_make_infty(int sign) { unsigned int bit_val_aui[] = {sign, MATH_EXP_MASK}; static int const bit_count_ai[] = { 1, IEEE754_EXP_SIZE}; return make_float(math_make_float(2,bit_val_aui,bit_count_ai)); } /* make infinitly small float number, with sign (this is same as signed 0.0 in IEEE754) */ static Lisp_Object math_make_epsilon(int is_neg) { double_map_ot double_map_o; int i = MATH_DOUBLE_INT_LSB; double_map_o.m_aui[i] = 0; while(i != MATH_DOUBLE_INT_MSB) { i += MATH_DOUBLE_INT_INC; double_map_o.m_aui[i] = 0; } if(is_neg) { double_map_o.m_aui[i] |= (1<<MATH_SIGN_POS); } return make_float(double_map_o.m_f); } /* return sign bit of x */ static int math_get_sign(double x) { double_map_ot double_map_o; double_map_o.m_f = x; return double_map_o.m_aui[MATH_DOUBLE_INT_MSB] >> MATH_SIGN_POS; } /* return biased exp value of x */ static unsigned int math_get_exp(double_map_ot dm_o) { int i = MATH_DOUBLE_INT_MSB; unsigned int word; int remain_count; int to_fill = sizeof(unsigned int)*8 - MATH_SIGN_POS; word = (dm_o.m_aui[i] << to_fill)>>to_fill; remain_count = IEEE754_EXP_SIZE-MATH_SIGN_POS; if(remain_count < 0) word >>= -remain_count; else while(remain_count > 0) { to_fill = remain_count; if(to_fill > sizeof(unsigned int)*8) to_fill = sizeof(unsigned int)*8; remain_count -= to_fill; if(remain_count < 0) { to_fill += remain_count; remain_count = 0; } word <<= to_fill; i += MATH_DOUBLE_INT_INC; word |= dm_o.m_aui[i] >> to_fill; } return word; } static unsigned int math_rotate_left(unsigned int what,int how_much) { what = (what<<how_much)|(what>>(sizeof(unsigned int)*8-how_much)); return what; } static unsigned int math_rotate_right(unsigned int what,int how_much) { what = (what>>how_much)|(what<<(sizeof(unsigned int)*8-how_much)); return what; } /* could be optimized if there is some intrinsic function */ #define MATH_ROTATE_LEFT(W,H) W = math_rotate_left(W,H) #define MATH_ROTATE_RIGHT(W,H) W = math_rotate_right(W,H) /* set biased exp value of x */ static void math_set_exp(double_map_ot* dm_po,unsigned int word) { int i = MATH_DOUBLE_INT_MSB; int remain_count = IEEE754_EXP_SIZE; int pos = MATH_SIGN_POS; int to_fill; for(;;) { unsigned int bit_val = dm_po->m_aui[i]; to_fill = pos; remain_count -= to_fill; if(remain_count < 0) { to_fill += remain_count; remain_count = 0; } /* bring exponent bits to lsb position */ pos -= to_fill; MATH_ROTATE_RIGHT(bit_val,pos); /* erase exponent bits */ bit_val >>= to_fill; bit_val <<= to_fill; /* fill exponent bits */ bit_val |= word>> remain_count; if(remain_count != 0) { /* no need to rotate left, if we get here this means that pos = 0*/ dm_po->m_aui[i] = bit_val; i += MATH_DOUBLE_INT_INC; pos = sizeof(unsigned int)*8; /* erase all bits in word that are more significant than the remain_count least significant bits*/ to_fill = pos-remain_count; word <<= to_fill; word >>= to_fill; } else { /* bring exponent bits back to orginal position */ MATH_ROTATE_LEFT(bit_val,pos); dm_po->m_aui[i] = bit_val; break; } } } #endif /* #########################################################################*/ /* public functions (visible from Lisp) */ /* =========================================================================*/ #ifdef HAVE_BINARY_IEEE754 DEFUN ("math-floatnum-binary-ieee754-formatter", Fmath_floatnum_binary_ieee754_formatter, Smath_floatnum_binary_ieee754_formatter, 4, 4, 0, doc: /* Formats floating point number into the binary IEEE754 floating point format used by native Lisp floating point numbers. When this number is not special, its value is : SIGN*MANTISSA * 2^EXPONENT where SIGN, MANTISSA and EXPONENT are numbers derived from IS-NEG, MANT and EXP arguments. 1. IS-NEG is t or nil, t for negative, and nil otherwise. SIGN is -1 for negative, and +1 otherwise. 2. IS-SPECIAL is `inf', `nan', `zero', `epsilon' or `nil' repectively for infinitly big, Not-a-Number, zero, infinitely small, and a normal non-zerofloating point number. 3. When IS-SPECIAL is non nil, MANT shall be nil, otherwise MANT shall be a non empty list of cons cells representing mantissa bits from most significant downto least significant: (N_k . B_k) (N_{k-1} . B_{k-1}) ... (N_1 . B_1) (N_0 . B_0) where N_i and B_i are integers such that for all i from 0 to k, 0 <B_i, and 0 =< N_i < 2^B_i and 2^{(B_k)-1} =< N_k and such that the MANTISSA can be written as \(N_0 + 2^B_0 * \(N_1 + 2^B_1 * \( ... \(N_{k-1}+2^B_{k-1}*N_k\) ...\)\)\) * 2^-(B_0+B_1+...+B_{k-1}+B_k - 1) That is to say the mantissa can be obtained by concatenating k binary words N_0 though N_k with respective bit counts B_0 through B_k, where N_k is the most significant part first in list, and N_0 the least significant one, last in the list, and by placing point just after the most significant bit. 4. EXP is an integer giving the exponent. Bias is not applied. In other words EXPONENT is directly equal to EXP.*/) (is_neg,is_special,mant,exp) Lisp_Object is_neg; Lisp_Object is_special; Lisp_Object mant; Lisp_Object exp; { register Lisp_Object val = Qnil; struct gcpro gcpro1, gcpro2, gcpro3, gcpro4; GCPRO4 (is_neg,is_special,mant,exp); CHECK_SYMBOL(is_neg); CHECK_SYMBOL(is_special); CHECK_NUMBER(exp); /* voir (elisp) Writing Emacs Primitives*/ if(NILP(is_special)) { double_map_ot double_map_o; int exp_val = XINT(exp); unsigned int word = 0; int i = MATH_DOUBLE_INT_MSB; /* add one, because of phantom bit */ int to_fill = 1+MATH_SIGN_POS; int bit_count; unsigned int bit_val; Lisp_Object elt; CHECK_LIST_CONS(mant,mant); /* remove phantom bit from first element of mantissa */ elt = XCAR(mant); mant = XCDR(mant); CHECK_NATNUM_CAR(elt); CHECK_NATNUM_CDR(elt); bit_val = XINT((XCAR (elt))); bit_count = XINT((XCDR (elt))); if(bit_count > 1) { --bit_count; { int to_erase = sizeof(unsigned int)*8-bit_count; bit_val <<= to_erase; bit_val >>= to_erase; } mant = Fcons( Fcons(make_number(bit_val),make_number(bit_count)), mant); } else if(bit_count != 1) error("invalid value for (cdar mant), shall be a positive integer"); /* bias the exponent, and push it to mant list*/ exp_val += MATH_EXP_BIAS; if(exp_val & ~MATH_EXP_MASK) error("Invalid exponent value"); mant = Fcons(Fcons(make_number(exp_val),make_number(IEEE754_EXP_SIZE)),mant); /* push sign to mant list */ bit_val = NILP(is_neg)?0:1; mant = Fcons(Fcons(make_number(bit_val),make_number(1)),mant); /* now read out mant list into double_map_o */ do { elt = XCAR(mant); mant = XCDR(mant); CHECK_NATNUM_CAR(elt); CHECK_NATNUM_CDR(elt); bit_val = XINT((XCAR (elt))); bit_count = XINT((XCDR (elt))); do { if(to_fill >= bit_count) { bit_val <<= (to_fill - bit_count); word |= bit_val; to_fill -= bit_count; bit_count = 0; } else { word |= bit_val>>(bit_count - to_fill); bit_count -= to_fill; /* erase all bits more significant than bit_count in bit_val */ to_fill = sizeof(unsigned int)*8 - bit_count; bit_val <<= to_fill; bit_val >>= to_fill; to_fill = 0; } if(to_fill == 0) { if(i == MATH_DOUBLE_INT_LSB) goto mant_complete; else to_fill = sizeof(unsigned int)*8; double_map_o.m_aui[i] = word; word = 0; i -= MATH_DOUBLE_INT_INC; } } while(bit_count != 0); } while (CONSP (mant)); mant_complete: do { double_map_o.m_aui[i] = word; word = 0; } while((i -= MATH_DOUBLE_INT_INC) != (MATH_DOUBLE_INT_LSB-MATH_DOUBLE_INT_INC)); val = make_float(double_map_o.m_f); } else { char const* is_special_symbol_name = (char const*)( SDATA (SYMBOL_NAME (is_special))); if(!EQ(mant,Qnil)) { error("mant shall be `nil' when is-special is non `nil'"); } if(strncmp (is_special_symbol_name, "zero", sizeof ("zero") - 1) == 0) { val = make_float(0.0); } else if(strncmp (is_special_symbol_name, "epsilon", sizeof ("epsilon") - 1) == 0) { val = math_make_epsilon(!NILP(is_neg)); } else if(strncmp (is_special_symbol_name, "nan", sizeof ("nan") - 1) == 0) { val = math_make_nan(!NILP(is_neg)); } else if(strncmp (is_special_symbol_name, "infty", sizeof ("infty") - 1) == 0) { val = math_make_infty(!NILP(is_neg)); } else error("unexpected symbol for is-special: %s",is_special_symbol_name); } UNGCPRO; return val; } #define MATH_IS_NEG ret[0] #define MATH_IS_SPECIAL ret[1] #define MATH_MANT ret[2] #define MATH_EXP ret[3] DEFUN ("math-floatnum-binary-ieee754-expander", Fmath_floatnum_binary_ieee754_expander, Smath_floatnum_binary_ieee754_expander, 1,1, 0, doc: /* Analyses a floating point number X conforming to the binary IEEE754 format used by Lisp floatingin point numbers, and returns a list \(IS-NEG IS-SPECIAL MANT EXP) where IS-NEG IS-SPECIAL MANT and EXP have the same meaning as in function `math-floatnum-binary-ieee754-formatter'.*/) (x) Lisp_Object x; { register Lisp_Object val = Qnil; Lisp_Object ret[4]; double_map_ot double_map_o; int exp_val,sign,i,j,bit_count,remain_count,filled,to_fill; unsigned int word,bit_val,pos; int bit_count_ai[2+MATH_MANT_LIST_SIZE]; unsigned int bit_val_aui[2+MATH_MANT_LIST_SIZE]; Lisp_Object mant_list[MATH_MANT_LIST_SIZE]; int is_mant_zero; CHECK_FLOAT(x); double_map_o.m_f = XFLOAT_DATA(x); bit_count_ai[0] = 1; /* sign bit size */ bit_count_ai[1] = IEEE754_EXP_SIZE; /* sign bit size */ remain_count = IEEE754_MANT_SIZE; i = 2; to_fill = (VALBITS-1)-1; /* first word shall have one spare bit for phantom */ do { to_fill = remain_count > to_fill ? to_fill: remain_count; bit_count_ai[i++] = to_fill; remain_count-= to_fill; to_fill = VALBITS-1; } while(remain_count != 0); /* analyse*/ remain_count = IEEE754_EXP_SIZE+IEEE754_MANT_SIZE+1; i = MATH_DOUBLE_INT_MSB; word = 0; filled = 0; j = 0; pos = 1+MATH_SIGN_POS; do { bit_val = double_map_o.m_aui[i]; i -= MATH_DOUBLE_INT_INC; if(remain_count > pos) { bit_count = pos; remain_count -= pos; } else { bit_val >>= pos - remain_count; bit_count = remain_count; remain_count = 0; } do { /* compute how many bits can be filled into word */ to_fill = bit_count; if(to_fill + filled > bit_count_ai[j]) to_fill = bit_count_ai[j] - filled; /* fill those bits into word, bit_count becomes the remaining number of bits in bit_val */ word <<= to_fill; bit_count -= to_fill; word |= bit_val>>bit_count; filled += to_fill; /* erase all bits of bit_val that are more significant than the bit_count least significant ones */ to_fill = sizeof(unsigned int)*8-bit_count; bit_val <<= to_fill; bit_val >>= to_fill; /* if there is no more room in word, then take the next item in mant_list */ if(filled == bit_count_ai[j]) { bit_val_aui[j++] = word; filled = 0; word = 0; } } while(bit_count != 0); pos = sizeof(unsigned int)*8; } while(remain_count != 0); /* end of analyse */ is_mant_zero = 1; for(i = 2; i < 2+MATH_MANT_LIST_SIZE; ++i) { if(bit_val_aui[i] != 0) { is_mant_zero = 0; break; } } /* check special values */ if(bit_val_aui[1] == 0 && is_mant_zero) { MATH_IS_SPECIAL = intern("zero"); MATH_MANT = Qnil; MATH_EXP = make_number(0); MATH_IS_NEG = bit_val_aui[0]?Qt:Qnil; } else if(bit_val_aui[1] == MATH_EXP_MASK) { /* Infinity or NaN */ if(is_mant_zero) { MATH_IS_SPECIAL = intern("infty"); } else { MATH_IS_SPECIAL = intern("nan"); } MATH_MANT = Qnil; MATH_EXP = make_number(0); MATH_IS_NEG = bit_val_aui[0]?Qt:Qnil; } else { /* normal number */ MATH_IS_SPECIAL = Qnil; /* restore phantom */ bit_val_aui[2] |= 1<<bit_count_ai[2]; ++bit_count_ai[2]; for(i = 0; i < MATH_MANT_LIST_SIZE; ++i) mant_list[i] = Fcons(make_number(bit_val_aui[i+2]), make_number(bit_count_ai[i+2])); MATH_MANT = Flist(MATH_MANT_LIST_SIZE,mant_list); MATH_EXP = make_number((int)bit_val_aui[1] - MATH_EXP_BIAS); MATH_IS_NEG = bit_val_aui[0]?Qt:Qnil; } val = Flist(4,ret); return val; } #endif /* #########################################################################*/ /* Syms of Calc */ /* =========================================================================*/ void syms_of_calc(void) { #ifdef HAVE_BINARY_IEEE754 defsubr (&Smath_floatnum_binary_ieee754_expander); defsubr (&Smath_floatnum_binary_ieee754_formatter); #endif DEFVAR_BOOL ("math-lisp-float-binary-ieee754-conformance", &math_lisp_float_binary_ieee754_conformance, doc: /* t if Lisp floats are conformant to one of the binary ieee754 format, nil otherwise */); math_lisp_float_binary_ieee754_conformance = #ifdef HAVE_BINARY_IEEE754 1 #else 0 #endif ; XSYMBOL (intern ("math-lisp-float-binary-ieee754-conformance"))->constant = 1; #ifdef HAVE_BINARY_IEEE754 DEFVAR_INT ("math-binary-ieee754-float-max-exp", &math_binary_ieee754_float_max_exp, doc: /* The largest exponent value for a lisp float, defined only on machines where lisp float are using one of the binary IEEE754 formats. */); math_binary_ieee754_float_max_exp = MATH_EXP_MASK-1-MATH_EXP_BIAS; XSYMBOL (intern ("math-binary-ieee754-float-max-exp"))->constant = 1; DEFVAR_INT ("math-binary-ieee754-float-min-exp", &math_binary_ieee754_float_min_exp, doc: /* The smalled exponent value for a lisp float, defined only on machines where lisp float are using one of the binary IEEE754 formats. */); math_binary_ieee754_float_min_exp = 1-MATH_EXP_BIAS; XSYMBOL (intern ("math-binary-ieee754-float-min-exp"))->constant = 1; DEFVAR_INT ("math-binary-ieee754-mant-size", &math_binary_ieee754_mant_size, doc: /* The number of bits in a binary IEEE754 mantissa, including the phantom bit. That is to say, the number of significant bits. */); math_binary_ieee754_mant_size = IEEE754_MANT_SIZE+1;/* add 1 for phantom*/ XSYMBOL (intern ("math-binary-ieee754-mant-size"))->constant = 1; #endif } /** mathfloat.c ends here*/ ^ permalink raw reply [flat|nested] 32+ messages in thread
* Re: Code for converting between Elisp and Calc floats 2009-10-22 18:56 ` Code for converting between Elisp and Calc floats Jay Belanger @ 2009-10-22 20:04 ` James Cloos 2009-10-23 0:50 ` Stefan Monnier 2009-10-23 13:11 ` Code for converting between Elisp and Calc floats Richard Stallman 2 siblings, 0 replies; 32+ messages in thread From: James Cloos @ 2009-10-22 20:04 UTC (permalink / raw) To: jay.p.belanger; +Cc: emacs-devel >>>>> "Jay" == Jay Belanger <jay.p.belanger@gmail.com> writes: Jay> +--------------------+----------------------------------------+ Jay> |10 |79bit binary IEEE is used by Lisp floats| Jay> +--------------------+----------------------------------------+ Jay> # elif (DBL_MANT_DIG == 1+64 \ Jay> && DBL_MIN_EXP == 1+-16382 \ Jay> && DBL_MAX_EXP == 1+16383) Jay> # define HAVE_DOUBLE_SIZEOF 10 Jay> # elif (DBL_MANT_DIG == 1+112 \ Jay> && DBL_MIN_EXP == 1+-16382 \ Jay> && DBL_MAX_EXP == 1+16383) Jay> # define HAVE_DOUBLE_SIZEOF 16 Jay> # else Jay> # define HAVE_DOUBLE_SIZEOF 0 Jay> # endif As there is no implied bit in the i387's 80-bit float; I suspect that the DBL_MANT_DIG == 1+64 will never match. Also -- and I've no idea whether this is relevant -- the 128 bit long doubles used on IBM's mainframes (and perhaps elsewhere) are the sum of two 64 bit doubles; they have more significant bits, but their exponents are no larger than a double. -JimC -- James Cloos <cloos@jhcloos.com> OpenPGP: 1024D/ED7DAEA6 ^ permalink raw reply [flat|nested] 32+ messages in thread
* Re: Code for converting between Elisp and Calc floats 2009-10-22 18:56 ` Code for converting between Elisp and Calc floats Jay Belanger 2009-10-22 20:04 ` James Cloos @ 2009-10-23 0:50 ` Stefan Monnier 2009-10-24 20:03 ` Jay Belanger 2009-10-23 13:11 ` Code for converting between Elisp and Calc floats Richard Stallman 2 siblings, 1 reply; 32+ messages in thread From: Stefan Monnier @ 2009-10-23 0:50 UTC (permalink / raw) To: jay.p.belanger; +Cc: emacs-devel > Vincent Belaïche has been working on making Calc more useful as an > Emacs library. Among the things he's working on is efficient > conversions between Calc floats and Elisp floats. This is best done > using some lisp functions that are written in C. Since it's C code, I > wanted an okay before I committed it. I have a copy of it at the end > of this message. The coding style needs to be adjusted: be careful with indentation, spacing around parentheses, placement of function names (at beginning of line, with the return type on the previous line), ... As for the feature itself, I'm not sure whether I like it. Could someone explain exactly what's the rationale behind this (e.g. a typical use case), what alternatives were considered, etc...? E.g. an "obvious" alternative would be to add builtin "big floats" via libgmp or some such. Also, I'm not sure I understand the code since it refers to 32, 64, 80, and 128bit floats, whereas Emacs normally only uses 64bit floats. Stefan > Thanks, > Jay > /** Code:*/ > #include <config.h> > #include "lisp.h" > #if HAVE_X_WINDOWS > #include "xterm.h" > #endif > #if STDC_HEADERS > #include <float.h> > #endif > /* if HAVE_DOUBLE_SIZEOF is not defined, then > try to define it from float.h, when possible, the > values in table below are considered. > Otherwise you may define it from the make command line if you > dare! > +--------------------+----------------------------------------+ > |HAVE_DOUBLE_SIZEOF |meaning | > +--------------------+----------------------------------------+ > |0 |binary IEEE754 is not used by Lisp | > | |floats, or Lisp floats are not supported| > +--------------------+----------------------------------------+ > |4 |32bit binary IEEE is used by Lisp floats| > | | | > +--------------------+----------------------------------------+ > |8 |64bit binary IEEE is used by Lisp floats| > +--------------------+----------------------------------------+ > |10 |79bit binary IEEE is used by Lisp floats| > +--------------------+----------------------------------------+ > |16 |128bit binary IEEE is used by Lisp | > | |floats | > +--------------------+----------------------------------------+ > */ > #ifndef HAVE_DOUBLE_SIZEOF > # if !defined LISP_FLOAT_TYPE \ > || !defined FLT_RADIX || !defined DBL_MANT_DIG \ > || !defined DBL_MIN_EXP || !defined DBL_MAX_EXP \ > || FLT_RADIX != 2 > # define HAVE_DOUBLE_SIZEOF 0 > # elif (DBL_MANT_DIG == 1+23 \ > && DBL_MIN_EXP == 1+-126 \ > && DBL_MAX_EXP == 1+127) > # define HAVE_DOUBLE_SIZEOF 4 > # elif (DBL_MANT_DIG == 1+52 \ > && DBL_MIN_EXP == 1+-1022 \ > && DBL_MAX_EXP == 1+1023) > # define HAVE_DOUBLE_SIZEOF 8 > # elif (DBL_MANT_DIG == 1+64 \ > && DBL_MIN_EXP == 1+-16382 \ > && DBL_MAX_EXP == 1+16383) > # define HAVE_DOUBLE_SIZEOF 10 > # elif (DBL_MANT_DIG == 1+112 \ > && DBL_MIN_EXP == 1+-16382 \ > && DBL_MAX_EXP == 1+16383) > # define HAVE_DOUBLE_SIZEOF 16 > # else > # define HAVE_DOUBLE_SIZEOF 0 > # endif > #endif > /* end of to be moved to config.h */ > /* #########################################################################*/ > /* Essential macro definitions for definition of IEEE754 format */ > /* =========================================================================*/ > #define HAVE_BINARY_IEEE754 1 > #ifdef HAVE_DOUBLE_SIZEOF > # if HAVE_DOUBLE_SIZEOF == 4 > # define IEEE754_EXP_SIZE 8 > # define IEEE754_MANT_SIZE 23/* no phantom*/ > # elif HAVE_DOUBLE_SIZEOF == 8 > # define IEEE754_EXP_SIZE 11 > # define IEEE754_MANT_SIZE 52/* no phantom*/ > # elif HAVE_DOUBLE_SIZEOF == 10 > # define IEEE754_EXP_SIZE 15 > # define IEEE754_MANT_SIZE 64/* no phantom*/ > # elif HAVE_DOUBLE_SIZEOF == 16 > # define IEEE754_EXP_SIZE 15 > # define IEEE754_MANT_SIZE 112/* no phantom*/ > # else > # undef HAVE_BINARY_IEEE754 > # endif > #else > # error incomplete config, missing HAVE_DOUBLE_SIZEOF > #endif > /* #########################################################################*/ > /* Lisp variables support in C */ > /* =========================================================================*/ > int math_lisp_float_binary_ieee754_conformance; > #ifdef HAVE_BINARY_IEEE754 > EMACS_INT math_binary_ieee754_float_max_exp, > math_binary_ieee754_float_min_exp, > math_binary_ieee754_mant_size; > #endif > /* #########################################################################*/ > /* Other macro definitions for handling of IEEE754 binary format */ > /* =========================================================================*/ > #ifdef HAVE_BINARY_IEEE754 > # define MATH_DOUBLE_INT_COUNT ((sizeof(double)+sizeof(unsigned int)-1)/sizeof(unsigned int)) > # define MATH_SIGN_POS (IEEE754_EXP_SIZE+IEEE754_MANT_SIZE \ > -(MATH_DOUBLE_INT_COUNT-1)*sizeof(unsigned int)*8) > # define MATH_EXP_MASK ((1<<IEEE754_EXP_SIZE)-1) > # define MATH_EXP_BIAS ((1<<(IEEE754_EXP_SIZE-1))-1) > # define MATH_MANT_LIST_SIZE ((IEEE754_MANT_SIZE+1 + VALBITS-2)/(VALBITS-1)) > # ifndef WORDS_BIG_ENDIAN > /* little endian case */ > # define MATH_DOUBLE_INT_LSB 0 > # define MATH_DOUBLE_INT_MSB (MATH_DOUBLE_INT_COUNT-1) > # define MATH_DOUBLE_INT_INC 1 > # else > /* big endian case */ > # define MATH_DOUBLE_INT_LSB (MATH_DOUBLE_INT_COUNT-1) > # define MATH_DOUBLE_INT_MSB 0 > # define MATH_DOUBLE_INT_INC -1 > # endif > typedef union union_double_map_ot > { > unsigned int m_aui[MATH_DOUBLE_INT_COUNT]; > double m_f; > } > double_map_ot; > #endif > /* #########################################################################*/ > /* Private functions */ > /* =========================================================================*/ > #ifdef HAVE_BINARY_IEEE754 > /* Produce a Not-a-Number. `sign' is the sign bit and shall be either 0 or 1. */ > static Lisp_Object math_make_nan(int sign) > { > double_map_ot double_map_o; > int i; > for(i = 0; i < MATH_DOUBLE_INT_COUNT; ++i) > double_map_o.m_aui[i] = ~0; > if(!sign) > double_map_o.m_aui[MATH_DOUBLE_INT_MSB] &= ~(1<<MATH_SIGN_POS); > return make_float(double_map_o.m_f); > } > /* fill a float starting from MSB*/ > static double math_make_float(int bitfield_count,unsigned int const bit_val_aui[],int const bit_count_ai[]) > { > double_map_ot double_map_o; > int j = 0; > int i = MATH_DOUBLE_INT_MSB; > unsigned int bit_val; > int bit_count; > int remain_count; > int to_fill; > unsigned int word = 0; > remain_count = 0; > for(j = 0; j < bitfield_count; ++j) > remain_count += bit_count_ai[j]; > to_fill = MATH_SIGN_POS+1; > bit_val = bit_val_aui[j = 0]; > bit_count = bit_count_ai[j++]; > for(;;) > { > if(to_fill >= bit_count) > { > bit_val <<= (to_fill - bit_count); > word |= bit_val; > remain_count -= bit_count; > to_fill -= bit_count; > bit_count = 0; > } > else > { > word |= bit_val>>(bit_count - to_fill); > bit_count -= to_fill; > remain_count -= to_fill; > /* erase all bits more significant than bit_count in > bit_val */ > to_fill = sizeof(unsigned int)*8 - bit_count; > bit_val <<= to_fill; > bit_val >>= to_fill; > to_fill = 0; > } > if(remain_count == 0) > goto fill_complete; > else if(remain_count < 0) > { > word <<= -remain_count; > goto fill_complete; > } > else > { > if(to_fill == 0) > { > double_map_o.m_aui[i] = word; > word = 0; > i -= MATH_DOUBLE_INT_INC; > to_fill = sizeof(unsigned int)*8; > } > if(bit_count == 0) > { > bit_val = bit_val_aui[j]; > bit_count = bit_count_ai[j++]; > } > } > } > fill_complete: > do > { > double_map_o.m_aui[i] = word; > word = 0; > } > while((i -= MATH_DOUBLE_INT_INC) != > (MATH_DOUBLE_INT_LSB-MATH_DOUBLE_INT_INC)); > /* printf("math_make_float: %ud %ud\n",double_map_o.m_aui[1],double_map_o.m_aui[0]);*/ > return double_map_o.m_f; > } > /* sign bit shall be 0 or 1 */ > static Lisp_Object math_make_infty(int sign) > { > unsigned int bit_val_aui[] = {sign, MATH_EXP_MASK}; > static int const bit_count_ai[] = { 1, IEEE754_EXP_SIZE}; > return make_float(math_make_float(2,bit_val_aui,bit_count_ai)); > } > /* make infinitly small float number, with sign (this is same as signed 0.0 in > IEEE754) */ > static Lisp_Object math_make_epsilon(int is_neg) > { > double_map_ot double_map_o; > int i = MATH_DOUBLE_INT_LSB; > double_map_o.m_aui[i] = 0; > while(i != MATH_DOUBLE_INT_MSB) > { > i += MATH_DOUBLE_INT_INC; > double_map_o.m_aui[i] = 0; > } > if(is_neg) > { > double_map_o.m_aui[i] |= (1<<MATH_SIGN_POS); > } > return make_float(double_map_o.m_f); > } > /* return sign bit of x */ > static int math_get_sign(double x) > { > double_map_ot double_map_o; > double_map_o.m_f = x; > return double_map_o.m_aui[MATH_DOUBLE_INT_MSB] >> MATH_SIGN_POS; > } > /* return biased exp value of x */ > static unsigned int math_get_exp(double_map_ot dm_o) > { > int i = MATH_DOUBLE_INT_MSB; > unsigned int word; > int remain_count; > int to_fill = sizeof(unsigned int)*8 - MATH_SIGN_POS; > word = (dm_o.m_aui[i] << to_fill)>>to_fill; > remain_count = IEEE754_EXP_SIZE-MATH_SIGN_POS; > if(remain_count < 0) > word >>= -remain_count; > else while(remain_count > 0) > { > to_fill = remain_count; > if(to_fill > sizeof(unsigned int)*8) > to_fill = sizeof(unsigned int)*8; > remain_count -= to_fill; > if(remain_count < 0) > { > to_fill += remain_count; > remain_count = 0; > } > word <<= to_fill; > i += MATH_DOUBLE_INT_INC; > word |= dm_o.m_aui[i] >> to_fill; > } > return word; > } > static unsigned int math_rotate_left(unsigned int what,int how_much) > { > what = (what<<how_much)|(what>>(sizeof(unsigned int)*8-how_much)); > return what; > } > static unsigned int math_rotate_right(unsigned int what,int how_much) > { > what = (what>>how_much)|(what<<(sizeof(unsigned int)*8-how_much)); > return what; > } > /* could be optimized if there is some intrinsic function */ > #define MATH_ROTATE_LEFT(W,H) W = math_rotate_left(W,H) > #define MATH_ROTATE_RIGHT(W,H) W = math_rotate_right(W,H) > /* set biased exp value of x */ > static void math_set_exp(double_map_ot* dm_po,unsigned int word) > { > int i = MATH_DOUBLE_INT_MSB; > int remain_count = IEEE754_EXP_SIZE; > int pos = MATH_SIGN_POS; > int to_fill; > for(;;) > { > unsigned int bit_val = dm_po->m_aui[i]; > to_fill = pos; > remain_count -= to_fill; > if(remain_count < 0) > { > to_fill += remain_count; > remain_count = 0; > } > /* bring exponent bits to lsb position */ > pos -= to_fill; > MATH_ROTATE_RIGHT(bit_val,pos); > /* erase exponent bits */ > bit_val >>= to_fill; > bit_val <<= to_fill; > /* fill exponent bits */ > bit_val |= word>> remain_count; > if(remain_count != 0) > { > /* no need to rotate left, if we get here this means that > pos = 0*/ dm_po-> m_aui[i] = bit_val; > i += MATH_DOUBLE_INT_INC; > pos = sizeof(unsigned int)*8; > /* erase all bits in word that are more significant than > the remain_count least significant bits*/ > to_fill = pos-remain_count; > word <<= to_fill; > word >>= to_fill; > } > else > { > /* bring exponent bits back to orginal position */ > MATH_ROTATE_LEFT(bit_val,pos); dm_po-> m_aui[i] = bit_val; > break; > } > } > } > #endif > /* #########################################################################*/ > /* public functions (visible from Lisp) */ > /* =========================================================================*/ > #ifdef HAVE_BINARY_IEEE754 > DEFUN ("math-floatnum-binary-ieee754-formatter", > Fmath_floatnum_binary_ieee754_formatter, > Smath_floatnum_binary_ieee754_formatter, > 4, 4, > 0, > doc: /* Formats floating point number into the binary IEEE754 floating > point format used by native Lisp floating point numbers. > When this number is not special, its value is : > SIGN*MANTISSA * 2^EXPONENT > where SIGN, MANTISSA and EXPONENT are numbers derived from > IS-NEG, MANT and EXP arguments. > 1. IS-NEG is t or nil, t for negative, and nil otherwise. SIGN is > -1 for negative, and +1 otherwise. > 2. IS-SPECIAL is `inf', `nan', `zero', `epsilon' or `nil' > repectively for infinitly big, Not-a-Number, zero, infinitely > small, and a normal non-zerofloating point number. > 3. When IS-SPECIAL is non nil, MANT shall be nil, otherwise MANT shall be a > non empty list of cons cells representing mantissa bits from most > significant downto least significant: > (N_k . B_k) (N_{k-1} . B_{k-1}) ... (N_1 . B_1) (N_0 . B_0) > where N_i and B_i are integers such that > for all i from 0 to k, > 0 <B_i, and > 0 =< N_i < 2^B_i > and 2^{(B_k)-1} =< N_k > and such that the MANTISSA can be written as > \(N_0 + 2^B_0 * > \(N_1 + 2^B_1 * > \( ... > \(N_{k-1}+2^B_{k-1}*N_k\) ...\)\)\) > * 2^-(B_0+B_1+...+B_{k-1}+B_k - 1) > That is to say the mantissa can be obtained by concatenating k binary words > N_0 though N_k with respective bit counts B_0 through B_k, where N_k is the > most significant part first in list, and N_0 the least significant one, last > in the list, and by placing point just after the most significant bit. > 4. EXP is an integer giving the exponent. Bias is not applied. In > other words EXPONENT is directly equal to EXP.*/) > (is_neg,is_special,mant,exp) > Lisp_Object is_neg; > Lisp_Object is_special; > Lisp_Object mant; > Lisp_Object exp; > { > register Lisp_Object val = Qnil; > struct gcpro gcpro1, gcpro2, gcpro3, gcpro4; > GCPRO4 (is_neg,is_special,mant,exp); > CHECK_SYMBOL(is_neg); > CHECK_SYMBOL(is_special); > CHECK_NUMBER(exp); > /* voir (elisp) Writing Emacs Primitives*/ > if(NILP(is_special)) > { > double_map_ot double_map_o; > int exp_val = XINT(exp); > unsigned int word = 0; > int i = MATH_DOUBLE_INT_MSB; > /* add one, because of phantom bit */ > int to_fill = 1+MATH_SIGN_POS; > int bit_count; > unsigned int bit_val; > Lisp_Object elt; > CHECK_LIST_CONS(mant,mant); > /* remove phantom bit from first element of mantissa */ > elt = XCAR(mant); > mant = XCDR(mant); > CHECK_NATNUM_CAR(elt); > CHECK_NATNUM_CDR(elt); > bit_val = XINT((XCAR (elt))); > bit_count = XINT((XCDR (elt))); > if(bit_count > 1) > { > --bit_count; > { > int to_erase = sizeof(unsigned int)*8-bit_count; > bit_val <<= to_erase; > bit_val >>= to_erase; > } > mant = Fcons( > Fcons(make_number(bit_val),make_number(bit_count)), > mant); > } > else if(bit_count != 1) > error("invalid value for (cdar mant), shall be a positive integer"); > /* bias the exponent, and push it to mant list*/ > exp_val += MATH_EXP_BIAS; > if(exp_val & ~MATH_EXP_MASK) > error("Invalid exponent value"); > mant = Fcons(Fcons(make_number(exp_val),make_number(IEEE754_EXP_SIZE)),mant); > /* push sign to mant list */ > bit_val = NILP(is_neg)?0:1; > mant = Fcons(Fcons(make_number(bit_val),make_number(1)),mant); > /* now read out mant list into double_map_o */ > do > { > elt = XCAR(mant); > mant = XCDR(mant); > CHECK_NATNUM_CAR(elt); > CHECK_NATNUM_CDR(elt); > bit_val = XINT((XCAR (elt))); > bit_count = XINT((XCDR (elt))); > do > { > if(to_fill >= bit_count) > { > bit_val <<= (to_fill - bit_count); > word |= bit_val; > to_fill -= bit_count; > bit_count = 0; > } > else > { > word |= bit_val>>(bit_count - to_fill); > bit_count -= to_fill; > /* erase all bits more significant than bit_count in > bit_val */ > to_fill = sizeof(unsigned int)*8 - bit_count; > bit_val <<= to_fill; > bit_val >>= to_fill; > to_fill = 0; > } > if(to_fill == 0) > { > if(i == MATH_DOUBLE_INT_LSB) > goto mant_complete; > else > to_fill = sizeof(unsigned int)*8; > double_map_o.m_aui[i] = word; > word = 0; > i -= MATH_DOUBLE_INT_INC; > } > } > while(bit_count != 0); > } > while (CONSP (mant)); > mant_complete: > do > { > double_map_o.m_aui[i] = word; > word = 0; > } > while((i -= MATH_DOUBLE_INT_INC) != > (MATH_DOUBLE_INT_LSB-MATH_DOUBLE_INT_INC)); > val = make_float(double_map_o.m_f); > } > else > { > char const* is_special_symbol_name = > (char const*)( SDATA (SYMBOL_NAME (is_special))); > if(!EQ(mant,Qnil)) > { > error("mant shall be `nil' when is-special is non `nil'"); > } > if(strncmp (is_special_symbol_name, > "zero", sizeof ("zero") - 1) == 0) > { > val = make_float(0.0); > } > else if(strncmp (is_special_symbol_name, > "epsilon", sizeof ("epsilon") - 1) == 0) > { > val = math_make_epsilon(!NILP(is_neg)); > } > else if(strncmp (is_special_symbol_name, > "nan", sizeof ("nan") - 1) == 0) > { > val = math_make_nan(!NILP(is_neg)); > } > else if(strncmp (is_special_symbol_name, > "infty", sizeof ("infty") - 1) == 0) > { > val = math_make_infty(!NILP(is_neg)); > } > else > error("unexpected symbol for is-special: %s",is_special_symbol_name); > } > UNGCPRO; > return val; > } > #define MATH_IS_NEG ret[0] > #define MATH_IS_SPECIAL ret[1] > #define MATH_MANT ret[2] > #define MATH_EXP ret[3] > DEFUN ("math-floatnum-binary-ieee754-expander", > Fmath_floatnum_binary_ieee754_expander, > Smath_floatnum_binary_ieee754_expander, > 1,1, > 0, > doc: /* > Analyses a floating point number X conforming to the binary > IEEE754 format used by Lisp floatingin point numbers, and returns > a list \(IS-NEG IS-SPECIAL MANT EXP) where > IS-NEG IS-SPECIAL MANT and EXP have the same meaning as in > function `math-floatnum-binary-ieee754-formatter'.*/) > (x) > Lisp_Object x; > { > register Lisp_Object val = Qnil; > Lisp_Object ret[4]; > double_map_ot double_map_o; > int exp_val,sign,i,j,bit_count,remain_count,filled,to_fill; > unsigned int word,bit_val,pos; > int bit_count_ai[2+MATH_MANT_LIST_SIZE]; > unsigned int bit_val_aui[2+MATH_MANT_LIST_SIZE]; > Lisp_Object mant_list[MATH_MANT_LIST_SIZE]; > int is_mant_zero; > CHECK_FLOAT(x); > double_map_o.m_f = XFLOAT_DATA(x); > bit_count_ai[0] = 1; /* sign bit size */ > bit_count_ai[1] = IEEE754_EXP_SIZE; /* sign bit size */ > remain_count = IEEE754_MANT_SIZE; > i = 2; > to_fill = (VALBITS-1)-1; /* first word shall have one spare bit for phantom */ > do > { > to_fill = remain_count > to_fill ? to_fill: remain_count; > bit_count_ai[i++] = to_fill; > remain_count-= to_fill; > to_fill = VALBITS-1; > } > while(remain_count != 0); > /* analyse*/ > remain_count = IEEE754_EXP_SIZE+IEEE754_MANT_SIZE+1; > i = MATH_DOUBLE_INT_MSB; > word = 0; > filled = 0; > j = 0; > pos = 1+MATH_SIGN_POS; > do > { > bit_val = double_map_o.m_aui[i]; > i -= MATH_DOUBLE_INT_INC; > if(remain_count > pos) > { > bit_count = pos; > remain_count -= pos; > } > else > { > bit_val >>= pos - remain_count; > bit_count = remain_count; > remain_count = 0; > } > do > { > /* compute how many bits can be filled into word */ > to_fill = bit_count; > if(to_fill + filled > bit_count_ai[j]) > to_fill = bit_count_ai[j] - filled; > /* fill those bits into word, bit_count becomes the remaining > number of bits in bit_val */ > word <<= to_fill; > bit_count -= to_fill; > word |= bit_val>>bit_count; > filled += to_fill; > /* erase all bits of bit_val that are more significant than > the bit_count least significant ones */ > to_fill = sizeof(unsigned int)*8-bit_count; > bit_val <<= to_fill; > bit_val >>= to_fill; > /* if there is no more room in word, then take the next item > in mant_list */ > if(filled == bit_count_ai[j]) > { > bit_val_aui[j++] = word; > filled = 0; > word = 0; > } > } > while(bit_count != 0); > pos = sizeof(unsigned int)*8; > } > while(remain_count != 0); > /* end of analyse */ > is_mant_zero = 1; > for(i = 2; i < 2+MATH_MANT_LIST_SIZE; ++i) > { > if(bit_val_aui[i] != 0) > { > is_mant_zero = 0; > break; > } > } > /* check special values */ > if(bit_val_aui[1] == 0 && is_mant_zero) > { > MATH_IS_SPECIAL = intern("zero"); > MATH_MANT = Qnil; > MATH_EXP = make_number(0); > MATH_IS_NEG = bit_val_aui[0]?Qt:Qnil; > } > else if(bit_val_aui[1] == MATH_EXP_MASK) > { > /* Infinity or NaN */ > if(is_mant_zero) > { > MATH_IS_SPECIAL = intern("infty"); > } > else > { > MATH_IS_SPECIAL = intern("nan"); > } > MATH_MANT = Qnil; > MATH_EXP = make_number(0); > MATH_IS_NEG = bit_val_aui[0]?Qt:Qnil; > } > else > { > /* normal number */ > MATH_IS_SPECIAL = Qnil; > /* restore phantom */ > bit_val_aui[2] |= 1<<bit_count_ai[2]; > ++bit_count_ai[2]; > for(i = 0; i < MATH_MANT_LIST_SIZE; ++i) > mant_list[i] = Fcons(make_number(bit_val_aui[i+2]), > make_number(bit_count_ai[i+2])); > MATH_MANT = Flist(MATH_MANT_LIST_SIZE,mant_list); > MATH_EXP = make_number((int)bit_val_aui[1] - MATH_EXP_BIAS); > MATH_IS_NEG = bit_val_aui[0]?Qt:Qnil; > } > val = Flist(4,ret); > return val; > } > #endif > /* #########################################################################*/ > /* Syms of Calc */ > /* =========================================================================*/ > void syms_of_calc(void) > { > #ifdef HAVE_BINARY_IEEE754 > defsubr (&Smath_floatnum_binary_ieee754_expander); > defsubr (&Smath_floatnum_binary_ieee754_formatter); > #endif > DEFVAR_BOOL ("math-lisp-float-binary-ieee754-conformance", > &math_lisp_float_binary_ieee754_conformance, > doc: /* t if Lisp floats are conformant to one of the binary > ieee754 format, nil otherwise */); > math_lisp_float_binary_ieee754_conformance = > #ifdef HAVE_BINARY_IEEE754 > 1 > #else > 0 > #endif > ; > XSYMBOL (intern ("math-lisp-float-binary-ieee754-conformance"))->constant = 1; > #ifdef HAVE_BINARY_IEEE754 > DEFVAR_INT ("math-binary-ieee754-float-max-exp", > &math_binary_ieee754_float_max_exp, > doc: /* The largest exponent value for a lisp float, defined only on machines where lisp float are using one of the binary IEEE754 formats. */); > math_binary_ieee754_float_max_exp = MATH_EXP_MASK-1-MATH_EXP_BIAS; > XSYMBOL (intern ("math-binary-ieee754-float-max-exp"))->constant = 1; > DEFVAR_INT ("math-binary-ieee754-float-min-exp", > &math_binary_ieee754_float_min_exp, > doc: /* The smalled exponent value for a lisp float, defined only on machines where lisp float are using one of the binary IEEE754 formats. */); > math_binary_ieee754_float_min_exp = 1-MATH_EXP_BIAS; > XSYMBOL (intern ("math-binary-ieee754-float-min-exp"))->constant = 1; > DEFVAR_INT ("math-binary-ieee754-mant-size", > &math_binary_ieee754_mant_size, > doc: /* The number of bits in a binary IEEE754 mantissa, including > the phantom bit. That is to say, the number of significant bits. */); > math_binary_ieee754_mant_size = IEEE754_MANT_SIZE+1;/* add 1 for phantom*/ > XSYMBOL (intern ("math-binary-ieee754-mant-size"))->constant = 1; > #endif > } > /** mathfloat.c ends here*/ ^ permalink raw reply [flat|nested] 32+ messages in thread
* Re: Code for converting between Elisp and Calc floats 2009-10-23 0:50 ` Stefan Monnier @ 2009-10-24 20:03 ` Jay Belanger 2009-10-25 0:56 ` Stefan Monnier 0 siblings, 1 reply; 32+ messages in thread From: Jay Belanger @ 2009-10-24 20:03 UTC (permalink / raw) To: emacs-devel; +Cc: jay.p.belanger Stefan Monnier <monnier@iro.umontreal.ca> writes: > As for the feature itself, I'm not sure whether I like it. > Could someone explain exactly what's the rationale behind this > (e.g. a typical use case), what alternatives were considered, etc...? Vincent explained this to me, but I expect he'll come along and do a better job explaining than I can. > E.g. an "obvious" alternative would be to add builtin "big floats" via > libgmp or some such. Using libgmp in Emacs has been discussed in the past, but as I recall hasn't had much support. Jay ^ permalink raw reply [flat|nested] 32+ messages in thread
* Re: Code for converting between Elisp and Calc floats 2009-10-24 20:03 ` Jay Belanger @ 2009-10-25 0:56 ` Stefan Monnier 2009-10-25 5:36 ` David Kastrup 0 siblings, 1 reply; 32+ messages in thread From: Stefan Monnier @ 2009-10-25 0:56 UTC (permalink / raw) To: jay.p.belanger; +Cc: vincent.belaiche, emacs-devel >> As for the feature itself, I'm not sure whether I like it. >> Could someone explain exactly what's the rationale behind this >> (e.g. a typical use case), what alternatives were considered, etc...? > Vincent explained this to me, but I expect he'll come along and do a > better job explaining than I can. Is he reading this thread? >> E.g. an "obvious" alternative would be to add builtin "big floats" via >> libgmp or some such. > Using libgmp in Emacs has been discussed in the past, but as I recall > hasn't had much support. It hasn't had much support indeed, mostly for lack of interest in bignums. But if we decide bignums deserve some C code, then maybe libgmp would be a good idea. Then again, without knowing the whys and hows, it's hard to tell. Stefan ^ permalink raw reply [flat|nested] 32+ messages in thread
* Re: Code for converting between Elisp and Calc floats 2009-10-25 0:56 ` Stefan Monnier @ 2009-10-25 5:36 ` David Kastrup 2009-10-25 11:36 ` Vincent Belaïche 2009-10-25 13:57 ` Stefan Monnier 0 siblings, 2 replies; 32+ messages in thread From: David Kastrup @ 2009-10-25 5:36 UTC (permalink / raw) To: emacs-devel Stefan Monnier <monnier@iro.umontreal.ca> writes: >>> As for the feature itself, I'm not sure whether I like it. >>> Could someone explain exactly what's the rationale behind this >>> (e.g. a typical use case), what alternatives were considered, etc...? >> Vincent explained this to me, but I expect he'll come along and do a >> better job explaining than I can. > > Is he reading this thread? > >>> E.g. an "obvious" alternative would be to add builtin "big floats" via >>> libgmp or some such. >> Using libgmp in Emacs has been discussed in the past, but as I recall >> hasn't had much support. > > It hasn't had much support indeed, mostly for lack of interest > in bignums. But if we decide bignums deserve some C code, then maybe > libgmp would be a good idea. Then again, without knowing the whys and > hows, it's hard to tell. There are few areas of importance. One would be buffer_size. Putting them transparently in there would imply having them all over the place in overlay positions, point and so on. I am also not sure that bignums of equal value compare as eq (floats don't) and there is likely code around relying on it. The buffer size problem would likely be less radically addressed by adding another bit of tagging, and then use half of the possible values for integers, giving a range of -2^30 .. 2^30-1. That's what XEmacs does, and it goes a far way of extending the point of nuisance. Of course calc could profit if one ripped out all of its multiple-precision list-based code (does not even use floats). But that would not require a transparent bignum type. An on-demand type would suffice. -- David Kastrup ^ permalink raw reply [flat|nested] 32+ messages in thread
* RE: Code for converting between Elisp and Calc floats 2009-10-25 5:36 ` David Kastrup @ 2009-10-25 11:36 ` Vincent Belaïche 2009-10-25 14:11 ` Chong Yidong 2009-10-25 13:57 ` Stefan Monnier 1 sibling, 1 reply; 32+ messages in thread From: Vincent Belaïche @ 2009-10-25 11:36 UTC (permalink / raw) To: emacs-devel [-- Attachment #1: Type: text/plain, Size: 208 bytes --] <87aazj2r7d.fsf_-_@vh213601.truman.edu> <jwv7hunkkf4.fsf-monnier+emacs@gnu.org> <87ws2kmuez.fsf@gmail.com> <jwvhbtoi9gj.fsf-monnier+emacs@gnu.org> <87hbto11d8.fsf@lola.goethe.zz> MIME-Version: 1.0 [-- Attachment #2: Type: text/plain, Size: 2958 bytes --] Hello, Sorry for coming so late into this thread. Thanks Jay for introducing my contribution, and thanks to you all for the feedback. I fully agree with most of the comments: * code presentation (indentation, commenting) probably needs some improvement (actually it took some time before I got something working well, and now I realize that I've neglected this aspect) * For your information "voir" just mean "see" in French, sorry for I forgot this in the code. Richard: if ever you get in touch with the French bureaucracy and have to fill in some form, then please remember that to fill an item by "void", just write "néant", * I developped and tested the code for the 64bit little endian float implementation of emacs (on a Mingw Windows2000 platform). I have put some code so that porting to other type of platform is easier, however I cannot guarantee that it would work at all for those ports. I did not know that emacs had 64bits floats only in all platform (and it seems to me quite unwise to base some code on the assumption that it will always & everywhere be that way). Now coming back to the contribution itself: of course we could discuss at length whether or not I did it the right way. However, we should first agree that there some need for having conversion function between Lisp floats and calc floats. Lisp float are the usual IEEE753 64bits radix 2 floats, while Calc floats are list based radix-10, configurable precision. The need which I see is that I often use calc as a math library. Native lisp has a few math primitives, however, when it comes to matrices, polynomials, and suchlikes, only Calc can make it. Most calc users use calc only as a Desk calculator, not as a math library. Most often I use it as a library for some preprocessor code that I include inline within some LaTeX document to generate some calculated texted values (I intend to make this preprocessor code public some day when it is mature enough, but I can provide draft code to anyone interested in it). When you use Calc as a library, then you would like it to interact more easily with some other piece of code, or simply to write the code more simply when the precision you need is only that of a 64bit float: nobody will deny that it is simpler to write: 0.5 instead of '(float 5 -1) However, currently calc do not accept numbers like 0.5 (those would be processed as if they were integers, and this causes at best an error throw, and at worst a buggy code). So if we come to the conclusion that indeed there is a need for Calc-to-Lisp + Lisp-to-Calc float conversion, then we can go into the next step of the discussion that is to discuss what is the best way to do it. Regards, Vincent. _________________________________________________________________ Nouveau ! Tout Windows débarque dans votre téléphone. Voir les Windows phone http://clk.atdmt.com/FRM/go/175819071/direct/01/ [-- Attachment #3: Type: text/html, Size: 3179 bytes --] ^ permalink raw reply [flat|nested] 32+ messages in thread
* Re: Code for converting between Elisp and Calc floats 2009-10-25 11:36 ` Vincent Belaïche @ 2009-10-25 14:11 ` Chong Yidong 2009-10-25 19:29 ` Vincent Belaïche 0 siblings, 1 reply; 32+ messages in thread From: Chong Yidong @ 2009-10-25 14:11 UTC (permalink / raw) To: Vincent Belaïche; +Cc: emacs-devel Vincent Belaïche <vincent.b.1@hotmail.fr> writes: > When you use Calc as a library, then you would like it to interact more easily > with some other piece of code, or simply to write the code more simply when the > precision you need is only that of a 64bit float: nobody will deny that it is > simpler to write: > > 0.5 > > instead of > > '(float 5 -1) Could you discuss why this needs built-in support? It should be possible to write a Lisp function or macro that automatically converts Lisp expressions based on Lisp floats into Lisp expressions based on calc floats. ^ permalink raw reply [flat|nested] 32+ messages in thread
* RE: Code for converting between Elisp and Calc floats 2009-10-25 14:11 ` Chong Yidong @ 2009-10-25 19:29 ` Vincent Belaïche 2009-10-26 2:30 ` Stefan Monnier 0 siblings, 1 reply; 32+ messages in thread From: Vincent Belaïche @ 2009-10-25 19:29 UTC (permalink / raw) To: cyd; +Cc: emacs-devel [-- Attachment #1: Type: text/plain, Size: 105 bytes --] <BLU104-W139663DC7482450EC1140284BB0@phx.gbl> <87d44bef7f.fsf@stupidchicken.com> MIME-Version: 1.0 [-- Attachment #2: Type: text/plain, Size: 3638 bytes --] Hello and thanks for the feedback, First, I would like to clarify that I was not aware of the issue of buffer size and pointer representation and that this was not my intent. Up to now, I have not felt concerned by this issue and have little idea on the best way to solve it, but my first feeling from the guts is that some kind of bigger-integer with fixed dynamic, e.g. 64bit integer would be a better option than arbitrary dynamic true bignums. Bignums should be really reserved for some math or financial things were you need no limitation. Then concerning the need for built-in support (point raised by cyd(string 64)stupidchicken.com), I fully agree that it is possible to do without it but as far as I made it, it was at the cost of some accuracy. First notes that the code that I submitted use built-in support only for a tiny part of the job that is kind-of bitwise access to IEEE754 floats, the main part of the job (the computation from radix 10 to radix 2) is entirely done in Lisp. So the built-in function are quite generic ones and could be used by other libraries needing to generate specific IEEE754 floats. Then also note that the Lisp code which I submitted actually contains both types of implementation: that using builtin support, and that not using it. The former is selected when the presence of builtin implementation is detected, while the other one should be selected otherwise (well I have not fully checked whether that switch works well). The reason why builtin support is needed is that without it there are losts of cases when some number that should convert without any loss of information, will suffer from some rounding error. This is error is in the magnitude of the quantization accuracy of the number, so it should not be too harmful: however I felt that it is a pity when you can get something better not to have it. The reason for this issue may be simply that the Lisp-only code which I wrote is not good enough, I have no formal proof that to that extent using builtin is a must. So if you can take this code and achieve to make it all Lisp, please feel free to do that. For instance if you could write Lisp only function doing exactly the same job as the builtin functions, then this would be quite an acceptable way to me. I did not try that, because I felt that it was so considerably more simple to do this in C than in Lisp, that I did not think that it would be an issue if this part is done in C, once people agree on the need for the contribution, and on the algorithm used to make the conversion, along with the split between the Lisp only part and the C code. Note that it took to me some time to make this work, the first attempt was a very simple Calc format to a string, followed by string to number, or vice versa. Then there was this lisp only implementation (that is still in the submitted code), and then only I made a novel implementation with the use of two builtin primitives. Vincent. > From: cyd@stupidchicken.com > To: vincent.b.1@hotmail.fr > Date: Sun, 25 Oct 2009 10:11:16 -0400 > CC: emacs-devel@gnu.org > Subject: Re: Code for converting between Elisp and Calc floats > [SNIP] > Could you discuss why this needs built-in support? It should be > possible to write a Lisp function or macro that automatically converts > Lisp expressions based on Lisp floats into Lisp expressions based on > calc floats. > > _________________________________________________________________ Nouveau Windows 7 : Simplifiez votre PC ! Trouvez le PC qui vous convient. http://clk.atdmt.com/FRM/go/181574580/direct/01/ [-- Attachment #3: Type: text/html, Size: 3910 bytes --] ^ permalink raw reply [flat|nested] 32+ messages in thread
* Re: Code for converting between Elisp and Calc floats 2009-10-25 19:29 ` Vincent Belaïche @ 2009-10-26 2:30 ` Stefan Monnier 2009-10-26 12:48 ` Vincent Belaïche 0 siblings, 1 reply; 32+ messages in thread From: Stefan Monnier @ 2009-10-26 2:30 UTC (permalink / raw) To: Vincent Belaïche; +Cc: cyd, emacs-devel > First, I would like to clarify that I was not aware of the issue of > buffer size and pointer representation and that this was not my > intent. Indeed it has nothing to do with the discussion at hand. > Then concerning the need for built-in support (point raised by > cyd(string 64)stupidchicken.com), I fully agree that it is possible to > do without it but as far as I made it, it was at the cost of > some accuracy. That's interesting, so the main purpose is accuracy. > First notes that the code that I submitted use built-in support only > for a tiny part of the job that is kind-of bitwise access to IEEE754 > floats, the main part of the job (the computation from radix 10 to > radix 2) is entirely done in Lisp. So the built-in function are quite > generic ones and could be used by other libraries needing to generate > specific IEEE754 floats. I didn't see this code, then (the code I saw only included C code). Could someone describe the general skeleton of the whole code (plus which part is in C, and what are the entry points)? > The reason why builtin support is needed is that without it there are > losts of cases when some number that should convert without any loss > of information, will suffer from some rounding error. This is error is > in the magnitude of the quantization accuracy of the number, so it > should not be too harmful: however I felt that it is a pity when you > can get something better not to have it. If you take (calc-in "3.5") as input rather than 3.5, then there is no such issue, right? > The reason for this issue may be simply that the Lisp-only code which > I wrote is not good enough, I have no formal proof that to that extent > using builtin is a must. So if you can take this code and achieve to > make it all Lisp, please feel free to do that. For instance if you > could write Lisp only function doing exactly the same job as the > builtin functions, then this would be quite an acceptable way to > me. I did not try that, because I felt that it was so considerably > more simple to do this in C than in Lisp, that I did not think that it > would be an issue if this part is done in C, once people agree on the > need for the contribution, and on the algorithm used to make the > conversion, along with the split between the Lisp only part and the > C code. I think I see what your two functions are doing, but I think their naming and interface is a bit more complex than needed. I'd suggest to drop the reference to ieee754 from the name and doc (they should just work for whatever floats are used internally, which in practice is just what `double' uses in the C compiler used to compile Emacs). Also, the mantissa should probably be represented as either a single integer or a list of integers where each integer provides 16bits of data (that's a format already used elsewhere in Emacs to represent "large integers" such as for time). You could rename them to something like construct-float and deconstruct-float. I'd also rename the mantissa and exponent size info, or maybe even consider providing it differently (in case its use is always linked to calls to one of the previous 2 functions, maybe those functions could return the relevant info. E.g. make-float could return the part of the mantissa it ignored). Since you're using those constants, you clearly know better how they're used, so I'll let you figure out whether there's a better way to ptovide the same info. Also, how is math-lisp-float-binary-ieee754-conformance used? > Note that it took to me some time to make this work, the first attempt > was a very simple Calc format to a string, followed by string to > number, or vice versa. What was the problem with this simple solution? Stefan ^ permalink raw reply [flat|nested] 32+ messages in thread
* RE: Code for converting between Elisp and Calc floats 2009-10-26 2:30 ` Stefan Monnier @ 2009-10-26 12:48 ` Vincent Belaïche 2009-10-27 3:22 ` Stefan Monnier 0 siblings, 1 reply; 32+ messages in thread From: Vincent Belaïche @ 2009-10-26 12:48 UTC (permalink / raw) To: monnier; +Cc: cyd, emacs-devel [-- Attachment #1: Type: text/plain, Size: 110 bytes --] <BLU104-W164CDF6A8CEB6630D267D484BB0@phx.gbl> <jwvljiyykp3.fsf-monnier+emacs@gnu.org> MIME-Version: 1.0 [-- Attachment #2.1: Type: text/plain, Size: 4403 bytes --] Hello Stefan, Thanks for your valuable feedback. I attached the Lisp part of the contribution. The entry point is just the two functions math-numfloat and math-floatnum. The former converts from Lisp to Calc, and the latter the other way round. > > If you take (calc-in "3.5") as input rather than 3.5, then there is no > such issue, right? > I just tried it (with setting math-lisp-float-binary-ieee754-conformance to nil so that no builtin support is used) (math-numfloat 3.5) evals correctly to (float 35 -1) but (math-floatnum '(float 35 -1)) evals to: 3.4999999999968168 Note that by default Calc has a 12 digit accuracy (that is less than a double that has almost 16 digit accuracy). So, to that extent, this latter conversion does not betray the accuracy of Calc (the 1st false digit is after 12 good digits). If I had used the version with builtin support, there would not be this issue (to be 100% frank I did not checked it just now, but I am quite confident that (math-floatnum '(float 35 -1)) would have evaluated to 3.5). [SNIP] > Also, the mantissa should probably be represented as either a single > integer or a list of integers where each integer provides 16bits of data > (that's a format already used elsewhere in Emacs to represent "large > integers" such as for time). > I did it this way because it allowed a simpler algorithm: in the conversion algorithm the integer size step is based on the number of decimal digits that Calc uses in representing big integers. The Calc big integers are not composed of 16bits integers (and actually there is not an integral number of bits, because these components are in radix 10). From that perspective it was easier if the number of bits of each component integer is passed along with the component integer in the interface. > You could rename them to something like construct-float and deconstruct-float. > No problem to rename them, I fully agree that what name you propose is better. > I'd also rename the mantissa and exponent size info, or maybe even > consider providing it differently (in case its use is always linked to > calls to one of the previous 2 functions, maybe those functions could > return the relevant info. E.g. make-float could return the part of the > mantissa it ignored). Since you're using those constants, you clearly > know better how they're used, so I'll let you figure out whether there's > a better way to ptovide the same info. > OK, this can be improved. Actually, my intention was not that these builtin functions were kind-of part of Calc library API, these are really internal things that the user developing above Calc should not need. > Also, how is math-lisp-float-binary-ieee754-conformance used? > This is the switch between the two types of implementations: the one using builtin support, and the one not needing builtin support. Note that I can imagine that it is possible to implement the construct/deconstruct builtin functions just using lisp, this is after all just a matter of generating clean powers of 2. But, since this code would be so machine/system dependant, and since Lisp would be so more uselessly complex than C code,I thought that it was a better choice to make it in C. > > Note that it took to me some time to make this work, the first attempt > > was a very simple Calc format to a string, followed by string to > > number, or vice versa. > > What was the problem with this simple solution? > String formatting/reading may depend on many parameters, including locale settings. It seemed to me unwise to go this way. You could of course use some default locale, and make all the settings in accordance with the objective of making this conversion, but conceptually I did not like the idea that you relie on functions whose objective is human/machine *interfacing* in order to make *computation*. Interfacing and Inner guts should be cleanly separate in any good software. These kind of function may depend on 3rd parties libraries from the compiling chain, there would certainly be porting issues, ... Vincent. > Stefan _________________________________________________________________ Nouveau Windows 7 : Trouvez le PC qui vous convient. En savoir plus. http://clk.atdmt.com/FRM/go/181574580/direct/01/ [-- Attachment #2.2: Type: text/html, Size: 4850 bytes --] [-- Attachment #3: mathfloat.el.gz --] [-- Type: application/x-gzip, Size: 4372 bytes --] ^ permalink raw reply [flat|nested] 32+ messages in thread
* Re: Code for converting between Elisp and Calc floats 2009-10-26 12:48 ` Vincent Belaïche @ 2009-10-27 3:22 ` Stefan Monnier 0 siblings, 0 replies; 32+ messages in thread From: Stefan Monnier @ 2009-10-27 3:22 UTC (permalink / raw) To: Vincent Belaïche; +Cc: cyd, emacs-devel >> Also, the mantissa should probably be represented as either a single >> integer or a list of integers where each integer provides 16bits of data >> (that's a format already used elsewhere in Emacs to represent "large >> integers" such as for time). > I did it this way because it allowed a simpler algorithm: in the > conversion algorithm the integer size step is based on the number of > decimal digits that Calc uses in representing big integers. The Calc > big integers are not composed of 16bits integers (and actually there > is not an integral number of bits, because these components are in > radix 10). From that perspective it was easier if the number of bits > of each component integer is passed along with the component integer > in the interface. I understand the code is simpler on the Lisp side, but I'm more concerned about the C side. Of course, if the Lisp side becomes unmanageable it's also relevant. >> I'd also rename the mantissa and exponent size info, or maybe even >> consider providing it differently (in case its use is always linked to >> calls to one of the previous 2 functions, maybe those functions could >> return the relevant info. E.g. make-float could return the part of the >> mantissa it ignored). Since you're using those constants, you clearly >> know better how they're used, so I'll let you figure out whether there's >> a better way to ptovide the same info. > OK, this can be improved. Actually, my intention was not that these > builtin functions were kind-of part of Calc library API, these are > really internal things that the user developing above Calc should > not need. I understand they're not Calc-specific althought they'd currently only be used by Calc. That's good. Still, Calc is the best sample-use we have, so it's what we have to guess at what a good API should look like. >> Also, how is math-lisp-float-binary-ieee754-conformance used? > This is the switch between the two types of implementations: the one > using builtin support, and the one not needing builtin support. So (fboundp 'construct-float) would work as well? > Note that I can imagine that it is possible to implement the > construct/deconstruct builtin functions just using Lisp, this is after > all just a matter of generating clean powers of 2. But, since this > code would be so machine/system dependant, and since Lisp would be so > more uselessly complex than C code,I thought that it was a better > choice to make it in C. I think it fits better in C. Basically, it would be the equivalent to C's frexp. Stefan ^ permalink raw reply [flat|nested] 32+ messages in thread
* Re: Code for converting between Elisp and Calc floats 2009-10-25 5:36 ` David Kastrup 2009-10-25 11:36 ` Vincent Belaïche @ 2009-10-25 13:57 ` Stefan Monnier 2009-10-25 18:35 ` Eli Zaretskii 1 sibling, 1 reply; 32+ messages in thread From: Stefan Monnier @ 2009-10-25 13:57 UTC (permalink / raw) To: David Kastrup; +Cc: emacs-devel > There are few areas of importance. One would be buffer_size. Putting bignums for buffer size is a bad idea. It would require an enormous amount of code changes and a very significant slow down (buffer positions are used extensively everywhere in the C code, including performance critical code such as the rendering engine, and changing them from scalar values to something else would slow things down tremendously). > The buffer size problem would likely be less radically addressed by > adding another bit of tagging, and then use half of the possible > values for integers, giving a range of -2^30 .. 2^30-1. Currently we have -2^28..2^28-1 and we can easily extend it to 2^29..2^29-1 without any noticeable downside (I have been using such a change for a while now). > That's what XEmacs does, and it goes a far way of extending the point > of nuisance. Not far enough, AFAICT: if you regularl edit files somewhere between 512M and 1G, then it's quite likely that you'll also want to edit files larger than 1G. Currently in 64bit mode, you supposedly can edit files larger but in practice when I tried it, I bumped into other bugs when reaching the 2G limit (or maybe even earlier) IIRC. Stefan ^ permalink raw reply [flat|nested] 32+ messages in thread
* Re: Code for converting between Elisp and Calc floats 2009-10-25 13:57 ` Stefan Monnier @ 2009-10-25 18:35 ` Eli Zaretskii 2009-10-26 2:02 ` Large files (was: Code for converting between Elisp and Calc floats) Stefan Monnier 0 siblings, 1 reply; 32+ messages in thread From: Eli Zaretskii @ 2009-10-25 18:35 UTC (permalink / raw) To: Stefan Monnier; +Cc: emacs-devel > From: Stefan Monnier <monnier@iro.umontreal.ca> > Date: Sun, 25 Oct 2009 09:57:49 -0400 > Cc: emacs-devel@gnu.org > > Currently in 64bit mode, you supposedly can edit files larger but in > practice when I tried it, I bumped into other bugs when reaching the > 2G limit (or maybe even earlier) IIRC. There are lots of places that use int instead of EMACS_INT. If we want to get full 64-bit buffer size, Someone(TM) should hunt them down and fix them. ^ permalink raw reply [flat|nested] 32+ messages in thread
* Large files (was: Code for converting between Elisp and Calc floats) 2009-10-25 18:35 ` Eli Zaretskii @ 2009-10-26 2:02 ` Stefan Monnier 0 siblings, 0 replies; 32+ messages in thread From: Stefan Monnier @ 2009-10-26 2:02 UTC (permalink / raw) To: Eli Zaretskii; +Cc: emacs-devel >> Currently in 64bit mode, you supposedly can edit files larger but in >> practice when I tried it, I bumped into other bugs when reaching the >> 2G limit (or maybe even earlier) IIRC. > There are lots of places that use int instead of EMACS_INT. If we > want to get full 64-bit buffer size, Someone(TM) should hunt them down > and fix them. I tracked down a fair number, but yes, there any many more. But last time I looked at it, I bumped into a bug that seemed to come from elsewhere (IIRC it appeared before the 2GB limit). Stefan ^ permalink raw reply [flat|nested] 32+ messages in thread
* Re: Code for converting between Elisp and Calc floats 2009-10-22 18:56 ` Code for converting between Elisp and Calc floats Jay Belanger 2009-10-22 20:04 ` James Cloos 2009-10-23 0:50 ` Stefan Monnier @ 2009-10-23 13:11 ` Richard Stallman 2009-10-23 13:26 ` David Kastrup 2 siblings, 1 reply; 32+ messages in thread From: Richard Stallman @ 2009-10-23 13:11 UTC (permalink / raw) To: jay.p.belanger; +Cc: jay.p.belanger, emacs-devel That code needs a lot more comments to explain what's happening. Also, would you please format the code in accord with the Emacs coding style? /* voir (elisp) Writing Emacs Primitives*/ if(NILP(is_special)) { double_map_ot double_map_o; int exp_val = XINT(exp); should be /* voir (elisp) Writing Emacs Primitives*/ if (NILP (is_special)) { double_map_ot double_map_o; int exp_val = XINT(exp); And why does it say "voir"? Is that French? Is it a typo for `void'? If it is a typo for `void', I don't understand the meaning. ^ permalink raw reply [flat|nested] 32+ messages in thread
* Re: Code for converting between Elisp and Calc floats 2009-10-23 13:11 ` Code for converting between Elisp and Calc floats Richard Stallman @ 2009-10-23 13:26 ` David Kastrup 2009-10-24 17:34 ` Richard Stallman 0 siblings, 1 reply; 32+ messages in thread From: David Kastrup @ 2009-10-23 13:26 UTC (permalink / raw) To: emacs-devel Richard Stallman <rms@gnu.org> writes: > That code needs a lot more comments to explain what's happening. > Also, would you please format the code in accord with the Emacs coding > style? > > /* voir (elisp) Writing Emacs Primitives*/ > if(NILP(is_special)) > { > double_map_ot double_map_o; > int exp_val = XINT(exp); > > should be > > /* voir (elisp) Writing Emacs Primitives*/ > if (NILP (is_special)) > { > double_map_ot double_map_o; > int exp_val = XINT(exp); > > > And why does it say "voir"? Is that French? Is it a typo for `void'? > If it is a typo for `void', I don't understand the meaning. It's basically "See (elisp) Writing Emacs Primitives" -- David Kastrup ^ permalink raw reply [flat|nested] 32+ messages in thread
* Re: Code for converting between Elisp and Calc floats 2009-10-23 13:26 ` David Kastrup @ 2009-10-24 17:34 ` Richard Stallman 0 siblings, 0 replies; 32+ messages in thread From: Richard Stallman @ 2009-10-24 17:34 UTC (permalink / raw) To: David Kastrup; +Cc: emacs-devel > And why does it say "voir"? Is that French? Is it a typo for `void'? > If it is a typo for `void', I don't understand the meaning. It's basically "See (elisp) Writing Emacs Primitives" Comments in Emacs should be written in English. I can guess what "voir" means here, since I speak French, but most Emacs hackers don't speak French. ^ permalink raw reply [flat|nested] 32+ messages in thread
* RE: Code for converting between Elisp and Calc floats @ 2009-10-27 4:56 Vincent Belaïche 2009-10-27 6:16 ` Stefan Monnier 0 siblings, 1 reply; 32+ messages in thread From: Vincent Belaïche @ 2009-10-27 4:56 UTC (permalink / raw) To: monnier; +Cc: cyd, emacs-devel [-- Attachment #1: Type: text/plain, Size: 3218 bytes --] Hello Stefan, > [SNIP] > > I understand the code is simpler on the Lisp side, but I'm more > concerned about the C side. Of course, if the Lisp side becomes > unmanageable it's also relevant. > For the C code anyhow, even if the integer component word size was not passed along in the interface, you would have anyhow to manage strange word sizes. This is because the mantissa is 53 bits, and 53 is not a multiple of 16. Also the mantissa is not aligned on the double word boundary (the sign + exponent not being a muliple of 16 bits) and you also have this phantom bit case to handle. I agree however that the C could have been slightly simpler if the integer component word size was forced to be 16bits. Maybe we could add one more layer in Lisp that would encapsulate the C function and add the word lengths to be 16 for those who would like to use the builtin function for other purpose, but with a simpler interface. This would basically achieve the interface that you envisionned as far as I can understand. Calc would however not use this additional layer of code. > [SNIP] > > This is the switch between the two types of implementations: the one > > using builtin support, and the one not needing builtin support. > > So (fboundp 'construct-float) would work as well? > Yes, definitely. That could be done this way, the reason why I used a specific variable is more historical than rational. > [SNIP] > I think it fits better in C. Basically, it would be the equivalent to > C's frexp. C++' frexp and ldexp are not a direct alternative, because the significand is still a non integer number (between 0.5 and 1 for frexp). So anyhow you would have to build clean powers of two to convert from the frexp returned significand to Calc internal mantissa that is an integer. Also the dynamic of the mantissa is higher than that of a Lisp integer, so any how you have so stick/split bits together/apart. However by combining calls to frexp, ldexp and floor one could get around. Frankly speaking, I must admit that I ignored the existance of frexp and ldexp standard functions. If I had known about them, maybe I would have tried to write the builtin functions with using only frexp ldexp and stuff like _isnan and suhclikes to handle special cases. That would have come at the cost of a slight additional processing cost, but this is completely neglectable in the case of Calc, due to the overhead of Lisp. Another alternative would be that frexp and ldexp and suhlikes are made builtin functions, and that the construct-float, deconstruct-float functions are in Lisp using those builtins: that would indeed be my preference if everyone thinks that the submitted C code is too complex. I am not sure however that re-coding those functions with frexp, ldexp and floor, would be that significantly less complex to justify the effort, now that I have already done the job in a more primitive way. Vincent. _________________________________________________________________ Nouveau ! Tout Windows débarque dans votre téléphone. Voir les Windows phone http://clk.atdmt.com/FRM/go/175819071/direct/01/ [-- Attachment #2: Type: text/html, Size: 3742 bytes --] ^ permalink raw reply [flat|nested] 32+ messages in thread
* Re: Code for converting between Elisp and Calc floats 2009-10-27 4:56 Vincent Belaïche @ 2009-10-27 6:16 ` Stefan Monnier 2009-10-27 19:38 ` Vincent Belaïche 0 siblings, 1 reply; 32+ messages in thread From: Stefan Monnier @ 2009-10-27 6:16 UTC (permalink / raw) To: Vincent Belaïche; +Cc: cyd, emacs-devel > For the C code anyhow, even if the integer component word size was not > passed along in the interface, you would have anyhow to manage strange > word sizes. This is because the mantissa is 53 bits, and 53 is not > a multiple of 16. Also the mantissa is not aligned on the double word > boundary (the sign + exponent not being a muliple of 16 bits) and you > also have this phantom bit case to handle. I think if you use frexp+floor, most of those issues won't matter much. >> I think it fits better in C. Basically, it would be the equivalent to >> C's frexp. > C++' frexp and ldexp are not a direct alternative, I understand. The interface you proposed is closer to what we'd like than what frexp has to offer. > Another alternative would be that frexp and ldexp and suhlikes are > made builtin functions, and that the construct-float, > deconstruct-float functions are in Lisp using those builtins: that > would indeed be my preference if everyone thinks that the submitted > C code is too complex. Actually my preference would be to keep the functionality you proposed (i.e. two functions (de)construct-float written in C), except force the base to be 65536 (i.e. 16bits per integer), and rewrite the C code to use standard functions like frexp, floor, isnan, and friends. Stefan ^ permalink raw reply [flat|nested] 32+ messages in thread
* RE: Code for converting between Elisp and Calc floats 2009-10-27 6:16 ` Stefan Monnier @ 2009-10-27 19:38 ` Vincent Belaïche 0 siblings, 0 replies; 32+ messages in thread From: Vincent Belaïche @ 2009-10-27 19:38 UTC (permalink / raw) To: monnier; +Cc: cyd, emacs-devel [-- Attachment #1: Type: text/plain, Size: 59 bytes --] <jwvocnte5aa.fsf-monnier+emacs@gnu.org> MIME-Version: 1.0 [-- Attachment #2: Type: text/plain, Size: 789 bytes --] > Actually my preference would be to keep the functionality you proposed > (i.e. two functions (de)construct-float written in C), except force the > base to be 65536 (i.e. 16bits per integer), and rewrite the C code to > use standard functions like frexp, floor, isnan, and friends. > Then I need some fonction to map the list of words with non-always-16-bit width to a list of words with 16-bit width. I would do this in Lisp with some use of `lsh' and `+', so that the Lisp part of my contribution could still use the same interface. Regards, Vincent. _________________________________________________________________ Nouveau Windows 7 : Trouvez le PC qui vous convient. En savoir plus. http://clk.atdmt.com/FRM/go/181574580/direct/01/ [-- Attachment #3: Type: text/html, Size: 1010 bytes --] ^ permalink raw reply [flat|nested] 32+ messages in thread
end of thread, other threads:[~2009-10-27 19:38 UTC | newest] Thread overview: 32+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2009-10-08 20:47 allow C-x v i / C-x v v to create a repository if none is available Dan Nicolaescu 2009-10-08 21:10 ` Chong Yidong 2009-10-09 19:18 ` Stefan Monnier 2009-10-09 19:32 ` Dan Nicolaescu 2009-10-13 18:40 ` Stefan Monnier 2009-10-13 15:59 ` Dan Nicolaescu 2009-10-21 19:06 ` Dan Nicolaescu 2009-10-23 7:45 ` Dan Nicolaescu 2009-10-23 13:12 ` Stefan Monnier 2009-10-24 2:34 ` Miles Bader 2009-10-24 6:35 ` Dan Nicolaescu 2009-10-22 18:56 ` Code for converting between Elisp and Calc floats Jay Belanger 2009-10-22 20:04 ` James Cloos 2009-10-23 0:50 ` Stefan Monnier 2009-10-24 20:03 ` Jay Belanger 2009-10-25 0:56 ` Stefan Monnier 2009-10-25 5:36 ` David Kastrup 2009-10-25 11:36 ` Vincent Belaïche 2009-10-25 14:11 ` Chong Yidong 2009-10-25 19:29 ` Vincent Belaïche 2009-10-26 2:30 ` Stefan Monnier 2009-10-26 12:48 ` Vincent Belaïche 2009-10-27 3:22 ` Stefan Monnier 2009-10-25 13:57 ` Stefan Monnier 2009-10-25 18:35 ` Eli Zaretskii 2009-10-26 2:02 ` Large files (was: Code for converting between Elisp and Calc floats) Stefan Monnier 2009-10-23 13:11 ` Code for converting between Elisp and Calc floats Richard Stallman 2009-10-23 13:26 ` David Kastrup 2009-10-24 17:34 ` Richard Stallman -- strict thread matches above, loose matches on Subject: below -- 2009-10-27 4:56 Vincent Belaïche 2009-10-27 6:16 ` Stefan Monnier 2009-10-27 19:38 ` Vincent Belaïche
Code repositories for project(s) associated with this external index https://git.savannah.gnu.org/cgit/emacs.git https://git.savannah.gnu.org/cgit/emacs/org-mode.git This is an external index of several public inboxes, see mirroring instructions on how to clone and mirror all data and code used by this external index.