|
Thanks to Harry and Jack, I believe that I have a solution to
my base64 encoding problem. Harry provided the base64 encoder.
Jack has shown how to recover the single precision float value
from the double precision float which SAS writes to memory
during a datastep. The last 4 bytes of the double float read
employing rb4 format yield the single precision float values.
I can POKE the single precision values into the correct slot
of a character variable of length N where N is the number of
MZ/Intensity pairs that I need to write. The base64 encoder
from Harry can be employed to write the output value. Below
is some code to illustrate.
/* Start of base64 encoder from Harry Droogendyk */
data exceptn;
label = '=';
hlo = 'O';
run;
data base64 (keep=fmtname start label hlo type);
retain fmtname "base64f"
type "N"
;
/*******************************
/* letters A-Z
/*******************************/
do start = 0 to 25;
label = byte(start+65);
output;
end;
/*******************************
/* letters a-z
/*******************************/
do start = 26 to 51;
label = byte(start+71);
output;
end;
/*******************************
/* numerals 0-9
/*******************************/
do start = 52 to 61;
label = byte(start-4);
output;
end;
/*******************************
/* special characters + /
/*******************************/
label = '+'; start = 62; output;
label = '/'; start = 63; output;
set exceptn ;
stop;
run;
proc format cntlin=base64;
run;
/* End of base64 encoder from Harry Droogendyk */
/* Use encoder to write base64 representation */
/* for 3 MZ/Intensity pairs */
data test;
/* Construct character variable Z of length 3 and */
/* return address for start of the character variable */
length z $3;
MemStart_z = addr(z);
/* Construct three MZ/Intensity paired values and */
/* write last 4 bytes of each value to incremented */
/* bins of character variable Z. */
put "Original 8 byte mz and intensity values";
do mz=427.338, 1096.701, 39374.893;
intensity=rannor(1234579);
put mz= intensity=; /* Show original values */
point+1;
MemStart_mz=addr(mz);
/* Put single precision mz value into appropriate bin of Z */
call poke(peekc(MemStart_mz+4,4),MemStart_z+4*(point-1));
point+1;
MemStart_Int = addr(intensity);
/* Put single precision intensity value into appropriate bin of Z
*/
call poke(peekc(MemStart_Int+4,4),MemStart_z+4*(point-1));
end;
/* See if I can recover mz and intensity values */
put / "Recovered 4 byte mz and intensity values";
do i=1 to point-1 by 2;
j=i+1;
mz = input(peekc(MemStart_z+4*(i-1)), rb4.);
intensity = input(peekc(MemStart_z+4*(j-1)), rb4.);
put mz= intensity=;
end;
/* Base64 encode character variable Z */
do i = 1 to length(Z) by 3;
do x = 1 to 4;
frmt = compress('bits6.' || (x-1)*6 );
chunk = inputn(substr(Z,i,3),frmt);
put chunk base64f. @;
end;
end;
run;
We certainly see some roundoff errors in the returned MZ/Intensity
values when they are recovered from just the last four bytes of
the double precision variables. However, that is something for
the mzXML standard to be concerned with. For my purpose of
being able to write a mzXML file as base64 encoded single precision
values all strung together in memory, I believe my problem is
solved.
Thanks!
Dale
--- Jack Hamilton <JackHamilton@FIRSTHEALTH.COM> wrote:
> Perhaps it's a byte-order problem? Compare with
>
> =====
> 409 data _null_;
> 410 length orig four char4 4
> 411 eight char8 8;
> 412 orig = 25;
> 413 z = addr(orig);
> 414 four = peek(z+4,4);
> 415 eight = peek(z,8);
> 416 char4 = input(peekc(z+4,4),rb4.);
> 417 char8 = input(peekc(z,8),rb8.);
> 418 put orig= four= eight= char4= char8=;
> 419 run;
>
> orig=25 four=1077477376 eight=25 char4=25 char8=25
> =====
>
>
>
>
> --
> JackHamilton@FirstHealth.com
> Manager, Technical Development
> Metrics Department, First Health
> West Sacramento, California USA
>
> Coelum, non animum mutant, qui trans mare currunt.
>
>
> >>> "Harry Droogendyk" <harry.droogendyk@RBC.COM> 01/05/2005 1:48 PM
> >>>
> Listers:
>
> In the quest to provide a fuller solution to Dale's base64 query, I
> encountered this. I'd surely appreciate the wisdom of y'all.
>
> Dale informed us that his data was stored in "single precision
> (4-byte) floats". Why doesn't PEEKing 4 bytes from the ADDRess of a
> 4 byte numeric variable ( i.e. a 4-byte float ) work? I'd expect
> variables FOUR and CHAR4 to have the correct values, they don't.
>
> 2359 data _null_;
> 2360 length orig four char4 4
> 2361 eight char8 8;
> 2362 orig = 25;
> 2363 z = addr(orig);
> 2364 four = peek(z,4);
> 2365 eight = peek(z,8);
> 2366 char4 = input(peekc(z,4),rb4.);
> 2367 char8 = input(peekc(z,8),rb8.);
> 2368 put orig= four= eight= char4= char8=;
> 2369 run;
>
> orig=25 four=0 eight=25 char4=0 char8=25
>
> TIA
=====
---------------------------------------
Dale McLerran
Fred Hutchinson Cancer Research Center
mailto: dmclerra@NO_SPAMfhcrc.org
Ph: (206) 667-2926
Fax: (206) 667-5977
---------------------------------------
__________________________________
Do you Yahoo!?
Read only the mail you want - Yahoo! Mail SpamGuard.
http://promotions.yahoo.com/new_mail
|