As you noted you can type d0
after the number. E.g.,
* 3.0d0
; => 3.0d0
* (type-of 3.0d0)
;=> DOUBLE-FLOAT
However, that's the literal notation for a double float, just like 1
is the literal notation for an integer. You can customize the default type of floating point numbers from the reader with *read-default-float-format*
, and Rainer Joswig's answer shows how. The declaration
(declare (type double-float x))
is a promise to the compiler that the value of the variable x
is a double float. You're lying to the compiler. To get a double float, you'll need to either write one as a literal (e.g., 1.0d0
) or convert one with the float
function:
* (float 1 0.0d0)
;=> 1.0d0
You could also use coerce
here:
* (coerce 1 'double-float)
;=> 1.0d0
When there's an option, it's reasonable to compare them. In SBCL, it turns out that these two options actually compile to the same thing:
CL-USER> (disassemble (compile nil (lambda (x) (coerce x 'double-float))))
; disassembly for (LAMBDA (X))
; 039C33E8: 488BD6 MOV RDX, RSI ; no-arg-parsing entry point
; 3EB: 488B059EFFFFFF MOV RAX, [RIP-98] ; #<FDEFINITION object for SB-KERNEL:%DOUBLE-FLOAT>
; 3F2: B908000000 MOV ECX, 8
; 3F7: FF7508 PUSH QWORD PTR [RBP+8]
; 3FA: FF6009 JMP QWORD PTR [RAX+9]
; 3FD: CC0A BREAK 10 ; error trap
; 3FF: 02 BYTE #X02
; 400: 18 BYTE #X18 ; INVALID-ARG-COUNT-ERROR
; 401: 54 BYTE #X54 ; RCX
NIL
CL-USER> (disassemble (compile nil (lambda (x) (float x 0.0d0))))
; disassembly for (LAMBDA (X))
; 03BC5B18: 488BD6 MOV RDX, RSI ; no-arg-parsing entry point
; 1B: 488B059EFFFFFF MOV RAX, [RIP-98] ; #<FDEFINITION object for SB-KERNEL:%DOUBLE-FLOAT>
; 22: B908000000 MOV ECX, 8
; 27: FF7508 PUSH QWORD PTR [RBP+8]
; 2A: FF6009 JMP QWORD PTR [RAX+9]
; 2D: CC0A BREAK 10 ; error trap
; 2F: 02 BYTE #X02
; 30: 18 BYTE #X18 ; INVALID-ARG-COUNT-ERROR
; 31: 54 BYTE #X54 ; RCX
NIL
It sounds like you're trying to do some automatic conversion, and I don't think you're going to find a way to do that. If you've got a number coming in, and you want a double-float
you'll have to convert it yourself. If you want to check that a value coming in is a double-float
you might have some luck with declarations, but a type declaration is just a promise to the compiler that something will have a particular type; this usually means that the compiler can omit checks since it's been promised that the value will have a certain type. That said, you might have some luck; in SBCL:
> (defun foo (x)
(declare (double-float x))
(+ x 2.0d0))
> (foo 3)
; The value 3 is not of type DOUBLE-FLOAT.
; [Condition of type TYPE-ERROR]
You might get different results if you change the safety optimization, though. If you want to ensure a type check, then use check-type
:
> (defun foo (x)
(check-type x double-float)
(+ x 2.0d0))
> (foo 3)
; The value of X is 3, which is not of type DOUBLE-FLOAT.
; [Condition of type SIMPLE-TYPE-ERROR]
declare
means, but doesn't tell me how to do what I'm wanting to do: which is to assure that the variables/calculations are double-float rather than the default. – Unaccomplisheddeclare
something to be a certain type, you are telling the compiler that you will take care for that variable to contain that specific type of value. The compiler won't take any actions to ensure this, on the contrary, it will assume that the type is as declared. Next, understand contagion - as the quote in Rainer Joswig's answer describes. :) – Mildencoerce
everywhere, it would determine precision based upon the precision of the parameters that I pass? And if those are variables, then the precision of those would depend upon what how those were previously computed? – Unaccomplished[1]> (/ 1 7) => 1/7
[2]> (/ 1 7.0) => 0.14285715
. And "precision" is a whole other game, you'd have to track the deltas etc. I know, you meant types. :) So where it's important, do usecoerce
, or some(+ ... 0.0d0)
tricks etc. -- CL is much more a VM than a language, by attitude. – Milden