Thread: [pure-lang-users] C float
Status: Beta
Brought to you by:
agraef
From: Eddie R. <er...@bm...> - 2008-08-12 21:02:02
|
If a function is defined in a C library as a float. How are we suppose to access it from Pure? e.r. |
From: Albert G. <Dr....@t-...> - 2008-08-13 02:02:33
|
Eddie Rucker wrote: > If a function is defined in a C library as a float. How are we suppose > to access it from Pure? Right, I'll have to add a 'float' type to 'extern' declarations. That should be easy to do, I have it on my TODO list now. Albert -- Dr. Albert Gr"af Dept. of Music-Informatics, University of Mainz, Germany Email: Dr....@t-..., ag...@mu... WWW: http://www.musikinformatik.uni-mainz.de/ag |
From: Albert G. <Dr....@t-...> - 2008-08-13 14:41:39
|
Eddie Rucker wrote: > If a function is defined in a C library as a float. How are we suppose > to access it from Pure? Ok, this is implemented now. Pure double arguments are truncated to float, and returned float results are expanded back to Pure doubles again. E.g.: > extern float expf(float); > expf 1.0; 2.71828174591064 -- Dr. Albert Gr"af Dept. of Music-Informatics, University of Mainz, Germany Email: Dr....@t-..., ag...@mu... WWW: http://www.musikinformatik.uni-mainz.de/ag |
From: Eddie R. <er...@bm...> - 2008-08-13 15:03:33
|
On Wed, 2008-08-13 at 16:41 +0200, Albert Graef wrote: > Eddie Rucker wrote: > > If a function is defined in a C library as a float. How are we suppose > > to access it from Pure? > > Ok, this is implemented now. Pure double arguments are truncated to > float, and returned float results are expanded back to Pure doubles > again. E.g.: > > > extern float expf(float); > > expf 1.0; > 2.71828174591064 > Thanks. What about const and unsigned parameters? So far, I've imported stuff like int foo(const char *bob, unsigned int hope) { as extern int foo(char *, int); However, I fear that some arithmetic (division?) on a variable before passing it to foo might get me some big bad ugly bug one day that will be near impossible to track down. e.r. |
From: John C. <co...@cc...> - 2008-08-13 15:16:30
|
Eddie Rucker scripsit: > Thanks. What about const and unsigned parameters? Casting away const is always safe: const essentially documents how the callee uses the argument or its referent. Unsigned does need explicit support to consistently get the right results: in particular, a too-big unsigned value should become a bignum. -- Man has no body distinct from his soul, John Cowan for that called body is a portion of the soul co...@cc... discerned by the five senses, http://www.ccil.org/~cowan the chief inlets of the soul in this age. --William Blake |
From: Eddie R. <er...@bm...> - 2008-08-13 16:09:01
|
On Wed, 2008-08-13 at 11:16 -0400, John Cowan wrote: > Eddie Rucker scripsit: > > > Thanks. What about const and unsigned parameters? > > Casting away const is always safe: const essentially documents how the callee > uses the argument or its referent. Ok. I understand this one. > Unsigned does need explicit support to consistently get the right results: > in particular, a too-big unsigned value should become a bignum. Hmm. I didn't even think about big numbers. I was worried about the following scenario: Some C library called f2.so defined by: unsigned int foo(unsigned int a) { return a + 1; } Then from Pure: > using "lib:/t2.so"; > extern int foo(int); > let a = 2147483646; > foo (a div -1); -2147483645 Now, the following C program gives different results: #include <stdio.h> unsigned int foo(unsigned int a) { return a + 1; } int main() { unsigned int a = 2147483646; printf("%d\n", foo(a/-1)); return 0; } Results: :~$ ./a.out 1 e.r. |
From: Albert G. <Dr....@t-...> - 2008-08-13 21:33:46
|
Eddie Rucker wrote: > Then from Pure: > > using "lib:/t2.so"; > > extern int foo(int); > > let a = 2147483646; > > foo (a div -1); > -2147483645 Nothing wrong there, a div -1 == -2147483646 in signed arithmetic, so foo (a div -1) == -2147483646+1 == -2147483645. > Now, the following C program gives different results: > [...] > unsigned int a = 2147483646; > > printf("%d\n", foo(a/-1)); Note that the 'a/-1' here does *unsigned* arithmetic (because you declared a as such), which means a/-1 == a/0xffffffffU == 0 != -2147483646 == (signed)a/-1. If you declare a as a signed int in your C program, you'll get exactly the same result as with Pure. Under all circumstances, the C interface should behave as if the C int type is "cast" to the Pure int type and vice versa (using truncation and sign extension as necessary), if that's not the case then please report it and I will fix it. I think that this is the most reasonable way to implement the marshalling of C ints considering the limited repertoire of integer types available in Pure. Of course, this means that a C unsigned int return value will become negative in Pure if it's big enough. But that can be easily undone with the following little Pure function which takes a Pure int x and returns a bigint equal to (unsigned)x in C: uint x::int = if x>=0 then bigint x else x+0x100000000L; This carries over to unsigned 8, 16 and 64 bit ints accordingly: ubyte x::int = if x>=0 then x else x+0x100; ushort x::int = if x>=0 then x else x+0x10000; ulong x::bigint = if x>=0 then x else x+0x10000000000000000L; These always use the smallest Pure int type capable of holding the result: int for ubyte and ushort, bigint for uint and ulong. (Note that in the case of 64 bit values the C interface returns a bigint, that's why ulong takes a bigint parameter.) Maybe I should add those definitions to primitives.pure? HTH, Albert -- Dr. Albert Gr"af Dept. of Music-Informatics, University of Mainz, Germany Email: Dr....@t-..., ag...@mu... WWW: http://www.musikinformatik.uni-mainz.de/ag |
From: Eddie R. <er...@bm...> - 2008-08-13 22:19:05
|
On Wed, 2008-08-13 at 23:34 +0200, Albert Graef wrote: > Under all circumstances, the C interface should behave as if the C int > type is "cast" to the Pure int type and vice versa (using truncation and > sign extension as necessary), if that's not the case then please report > it and I will fix it. I think that this is the most reasonable way to > implement the marshalling of C ints considering the limited repertoire > of integer types available in Pure. I don't know yet. If it doesn't cause any problems then we should leave it alone. > Of course, this means that a C unsigned int return value will become > negative in Pure if it's big enough. But that can be easily undone with > the following little Pure function which takes a Pure int x and returns > a bigint equal to (unsigned)x in C: > > uint x::int = if x>=0 then bigint x else x+0x100000000L; > > This carries over to unsigned 8, 16 and 64 bit ints accordingly: > > ubyte x::int = if x>=0 then x else x+0x100; > ushort x::int = if x>=0 then x else x+0x10000; > ulong x::bigint = if x>=0 then x else x+0x10000000000000000L; > > These always use the smallest Pure int type capable of holding the > result: int for ubyte and ushort, bigint for uint and ulong. (Note that > in the case of 64 bit values the C interface returns a bigint, that's > why ulong takes a bigint parameter.) > > Maybe I should add those definitions to primitives.pure? Maybe. My concern was mostly the parameters to a C function in a library where one of the arguments was an unsigned int. We certainly cannot pass a bigint can we? I know we can treat a signed int or unsigned the same and I don't see it as much of a problem. I just get a bad feeling when arithmetic is involved on a parameter during the call. I don't know maybe I shouldn't be so concerned. e.r. |
From: Albert G. <Dr....@t-...> - 2008-08-14 23:54:00
|
Albert Graef wrote: > Eddie Rucker wrote: >> Maybe. My concern was mostly the parameters to a C function in a library >> where one of the arguments was an unsigned int. > > Just pretend that it's an int in the extern declaration. That should > just work (FLW), even if you pass it a bigint (which gives you the > necessary range to represent all unsigned int values). No, it doesn't right now. Only 'long' arguments allow a bigint parameter right now. But it's easy to extend this to the other C int types (char, short, int), I'm working on that. Albert -- Dr. Albert Gr"af Dept. of Music-Informatics, University of Mainz, Germany Email: Dr....@t-..., ag...@mu... WWW: http://www.musikinformatik.uni-mainz.de/ag |
From: Albert G. <Dr....@t-...> - 2008-08-13 22:41:00
|
Eddie Rucker wrote: > Maybe. My concern was mostly the parameters to a C function in a library > where one of the arguments was an unsigned int. Just pretend that it's an int in the extern declaration. That should just work (FLW), even if you pass it a bigint (which gives you the necessary range to represent all unsigned int values). I'll write some test programs later this week to verify that the C interface does the right thing in all these cases. > I don't know maybe I shouldn't be so concerned. "Don't worry, be happy." :) Albert (still in vacation mode, obviously ;-) -- Dr. Albert Gr"af Dept. of Music-Informatics, University of Mainz, Germany Email: Dr....@t-..., ag...@mu... WWW: http://www.musikinformatik.uni-mainz.de/ag |
From: Albert G. <Dr....@t-...> - 2008-08-14 13:38:52
|
Albert Graef wrote: > uint x::int = if x>=0 then bigint x else x+0x100000000L; > [...] > Maybe I should add those definitions to primitives.pure? Done. -- Dr. Albert Gr"af Dept. of Music-Informatics, University of Mainz, Germany Email: Dr....@t-..., ag...@mu... WWW: http://www.musikinformatik.uni-mainz.de/ag |
From: Albert G. <Dr....@t-...> - 2008-08-13 19:53:09
|
John Cowan wrote: > Casting away const is always safe: const essentially documents how the callee > uses the argument or its referent. Exactly. The most important thing you have to keep in mind is that if a C routine returns a const pointer, you're not supposed to modify the data in Pure. And if a C routine takes a const pointer as argument, you can pass it any pointer from Pure (malloced memory, string, etc.) and be confident that the C routine won't modify it. Pure also takes care of marshalling Pure strings from/to the system encoding if the corresponding C type in the Pure extern declaration is char*. That usually does the right thing for const char* arguments and return values on the C side. Where things get a bit messy is when you have to pass *non-const* pointers as arguments or get them as results. A non-const pointer _argument_ is most likely used to return results; in that case you'll usually have to malloc some memory to be passed for that parameter, maybe initialize the data as required by the C function and decode the results and free the memory after the function returns. A non-const pointer _return value_ (which isn't also a non-const parameter, such as in strcpy) often indicates data malloced by the C routine which is supposed to be freed by the caller (i.e., the Pure program). Albert -- Dr. Albert Gr"af Dept. of Music-Informatics, University of Mainz, Germany Email: Dr....@t-..., ag...@mu... WWW: http://www.musikinformatik.uni-mainz.de/ag |
From: Albert G. <Dr....@t-...> - 2008-08-15 10:56:29
|
Albert Graef wrote: >> Just pretend that it's an int in the extern declaration. That should >> just work (FLW), even if you pass it a bigint (which gives you the >> necessary range to represent all unsigned int values). > > No, it doesn't right now. Only 'long' arguments allow a bigint parameter > right now. But it's easy to extend this to the other C int types (char, > short, int), I'm working on that. Ok, I've implemented this, so if you need to pass an unsigned int constant which is too big to be represented as a positive Pure int then you can just pass a bigint instead. This works with all C int types now. (In fact, since int constants are converted to bigints automatically when they fall outside the int range, even something like foo 0xffffffff will do the right thing.) For unsigned return values, you can use the appropriate uint et al routines, as discussed previously. I consider this fixed now. Cue the "Don't worry..." song again. ;-) Albert -- Dr. Albert Gr"af Dept. of Music-Informatics, University of Mainz, Germany Email: Dr....@t-..., ag...@mu... WWW: http://www.musikinformatik.uni-mainz.de/ag |
From: Eddie R. <er...@bm...> - 2008-08-15 12:34:01
|
On Fri, 2008-08-15 at 12:57 +0200, Albert Graef wrote: > Albert Graef wrote: > >> Just pretend that it's an int in the extern declaration. That should > >> just work (FLW), even if you pass it a bigint (which gives you the > >> necessary range to represent all unsigned int values). > > > > No, it doesn't right now. Only 'long' arguments allow a bigint parameter > > right now. But it's easy to extend this to the other C int types (char, > > short, int), I'm working on that. > > Ok, I've implemented this, so if you need to pass an unsigned int > constant which is too big to be represented as a positive Pure int then > you can just pass a bigint instead. This works with all C int types now. > (In fact, since int constants are converted to bigints automatically > when they fall outside the int range, even something like foo 0xffffffff > will do the right thing.) For unsigned return values, you can use the > appropriate uint et al routines, as discussed previously. > > I consider this fixed now. Cue the "Don't worry..." song again. ;-) Happy +1 ;-) e.r. |