[Search for users] [Overall Top Noters] [List of all Conferences] [Download this site]

Conference rusure::math

Title:Mathematics at DEC
Moderator:RUSURE::EDP
Created:Mon Feb 03 1986
Last Modified:Fri Jun 06 1997
Last Successful Update:Fri Jun 06 1997
Number of topics:2083
Total number of notes:14613

177.0. "Vax date/time math" by CHAOS::DICKENS () Mon Nov 12 1984 17:51

I am looking for a set of VAX high-level language callable routines to
do addition, subtraction and comparison (<,>,=) of quadword integers,
the VAX system date & time format.   I am not a math whiz.

I have seen a package called IXP, but it seems that it would require
me to constantly convert back and forth between the single quadword
format and a (different?) IXP format.  My rather crude attempts
at doing this were unsucessful.

Does anyone have working routines for dealing with quadword integers
as they are ?  This would be the best for my purpose.

If not, does anyone have an example of IXP used to do quadword integer
math ?  I'd need to know how to convert a quadword integer to an IXP 
integer and back again.

I program in VAX Pascal, and here's an example of data type I'm using:

TYPE
	$QUAD	= [QUAD,UNSAFE] RECORD
	L0:UNSIGNED; L1:INTEGER; END;

It's stolen directly from STARLET.PAS, and it works fine with the the
VAX system services for dealing with dates & times.

Here's a scenario to give you an idea of why I need this:  I have
an absolute time to which I want to add a delta time to get another
absolute time in the future.  I can use a system service call to get
the delta time in system format, but then I have no way to add the two !

I figure that the routines must exist somewhere, since the VMS queueing
services, for one, have to do this kind of thing all the time.

Thanks in advance, everyone, for any time you spend on this.

					-Jeff Dickens

T.RTitleUserPersonal
Name
DateLines
177.1HARE::STANTue Nov 13 1984 16:026
But the VAX architecture has hardware instructions that do these
things.  For efficiency, you should be using them! So code in
MACRO or BLISS.  Since we have a common language environment,
you can just have some small macro routines that do these
things for you and then write the rest of your application
in some other language.
177.2HARE::STANTue Nov 13 1984 16:053
Also, have you looked through the RTL manual?
There are several RTL routines that may be of some
use to you, such as LIB$EDIV, LIB$EMUL, LIB$ADDX, and LIB$SUBX.
177.3AURORA::HALLYBWed Nov 14 1984 11:524
Contact Richard NEWTON::KITTELL, who wrote some Pascal routines that call IXP
to do date arithmetic.

							John
177.4ORPHAN::BRETTTue Nov 27 1984 14:474
In Bliss, there's is ADDM etc...

/Bevin
177.5CHAOS::DICKENSFri Dec 07 1984 14:07222
Well, I've gotten somewhere from the IXP angle.  Here is what I have.

Now my major problem is that IXP doesn't seem to deal well with the
kind of negative number generated by calling $BINTIM with a delta time.

------
sample output:

time sample	:	 7-DEC-1984 14:01:20.92
value		:	39779928809200000
delta time	:	17-NOV-1858 00:10:00.00
value		:	6000000000
result time	:	 7-DEC-1984 14:11:20.92
value		:	39779934809200000

------
program listing:

[INHERIT ('SYS$LIBRARY:STARLET')]

{

	The point of this program is to work out the details of using
	ixp to add, subtract & compare vax-format dates & times.

	So far it all works, except that the ixp representation of 
	a delta time doesn't come out right.  It looks like a very
	large number instead of a reasonably sized negative number.

	The reason I'm doing this is to eventually develop a generalized
	set of routines for adding, subtracting and comparing dates.
	Eventually, I'd like to replace the IXP calls with calls to
	macro routines that would use hardware instructions to add,
	subtract and compare quadwords.  Until then, I have to get 
	this working so I can go ahead with the program.

	This is strictly a midnight hack.

						-Jeff RDVAX:: Dickens
}


PROGRAM TESTIXP(input,output);

%INCLUDE 'SYS$LIBRARY:PASSTATUS.PAS/NOLIST'

TYPE
	$BYTE = [BYTE] -128..127;
	$WORD = [WORD] -32768..32767;
	$QUAD = [QUAD,UNSAFE] RECORD
		L0:UNSIGNED; L1:INTEGER; END;
	$OCTA = [OCTA,UNSAFE] RECORD
		L0,L1,L2:UNSIGNED; L3:INTEGER; END;
	$UBYTE = [BYTE] 0..255;
	$UWORD = [WORD] 0..65535;
	$UQUAD = [QUAD,UNSAFE] RECORD
		L0,L1:UNSIGNED; END;
	$UOCTA = [OCTA,UNSAFE] RECORD
		L0,L1,L2,L3:UNSIGNED; END;

	timbuf_type	=	PACKED ARRAY [1..23] OF CHAR;
	{String to buffer ascii time in}

    VAX_DESC = [ALIGNED(2)] RECORD		{for IXP arithmetic}
	DSC$W_LENGTH : $WORD;
	DSC$B_DTYPE  : $BYTE;
	DSC$B_CLASS  : $BYTE;
	DSC$A_POINTER: [UNSAFE] UNSIGNED;
	END;

    IXP_DESC = [ALIGNED(2)] RECORD		{for IXP arithmetic}
	LENGTH : $UWORD;
	MBZ    : [POS(16), BIT(15)] 0..32767;
	SIGN   : [POS(31), BIT] 0..1;
	DATE   : [POS(32)] $QUAD;
	END;

VAR

	length : $UWORD;
	{length for IXP$CVTXA calls}

	value_str : [volatile] PACKED ARRAY [1..80] OF CHAR;
	{buffer for IXP$CVTXA calls}
	
	time_sample, delta_time, result_time 
	,ixp_value :
						[VOLATILE]VAX_DESC;
	{ixp date descriptors}

	time_sample_ixp, delta_time_ixp, result_time_ixp :
						[VOLATILE]IXP_DESC;
	{ixp dates themselves}
	
	status		: 	INTEGER;
	{status return for external calls}

	time_buffer	:	timbuf_type;
	{String to buffer ascii time in}

[EXTERNAL, ASYNCHRONOUS] PROCEDURE LIB$SIGNAL
    (%IMMED Condition : UNSIGNED;
     %IMMED FAO_Params : [LIST, UNSAFE] INTEGER := %IMMED 0);
    EXTERNAL;

{* The IXP package is used for date (quadword) arithmetic. Information and
   objects for the package are available at AURORA::IXP.*   *}

[EXTERNAL] FUNCTION IXP$MULXN
    (MULR : VAX_DESC;
     MULD : VAX_DESC;
     PROD : VAX_DESC) :
    INTEGER;
    EXTERNAL;

[EXTERNAL] FUNCTION IXP$CVTLX
    (FROM_INT : INTEGER;
     TO_IXP   : VAX_DESC) :
    INTEGER;
    EXTERNAL;

[EXTERNAL] FUNCTION IXP$CVTXA 
    (NUMBER_IXP : VAX_DESC;
     BUFFER : VAX_DESC;
     VAR LENGTH : $UWORD) :
    INTEGER;
    EXTERNAL;

[EXTERNAL] FUNCTION IXP$ADDXN
    (ADD1 : VAX_DESC;
     ADD2 : VAX_DESC;
     SUM  : VAX_DESC) :
    INTEGER;
    EXTERNAL;

[EXTERNAL] FUNCTION IXP$SUBXN
    (ADD1 : VAX_DESC;
     ADD2 : VAX_DESC;
     SUM  : VAX_DESC) :
    INTEGER;
    EXTERNAL;

BEGIN

ixp_value.DSC$W_LENGTH := 80;
ixp_value.DSC$A_POINTER := ADDRESS(value_str);
{set up descriptor for buffer for ixp$cvtxa calls}

time_sample.DSC$W_LENGTH := 12;
time_sample.DSC$A_POINTER := ADDRESS(time_sample_ixp);
time_sample_ixp.LENGTH := 8;
time_sample_ixp.MBZ := 0;
time_sample_ixp.SIGN := 0;
{init ixp & descriptor for time_sample}

delta_time.DSC$W_LENGTH := 12;
delta_time.DSC$A_POINTER := ADDRESS(delta_time_ixp);
delta_time_ixp.LENGTH := 8;
delta_time_ixp.MBZ := 0;
delta_time_ixp.SIGN := 0;
{init ixp & descriptor for delta_time}

result_time.DSC$W_LENGTH := 12;
result_time.DSC$A_POINTER := ADDRESS(result_time_ixp);
result_time_ixp.LENGTH := 8;
result_time_ixp.MBZ := 0;
result_time_ixp.SIGN := 0;
{init ixp & descriptor for result_time}

status := $GETTIM(time_sample_ixp.DATE);		{get current time}
time_buffer := '                       ';		{clear buffer}
status := $ASCTIM(,time_buffer,time_sample_ixp.DATE);	{convert to ascii}
WRITELN('time sample	:	',time_buffer);		{print ascii date}
status := IXP$CVTXA(time_sample,ixp_value,length);  {convert ixp xn to ascii}
WRITELN('value		:	',value_str:length);	{print ixp value}

{
	Note that here I found that I couldn't deal with IXP version
	of a delta time, because it's twos complement negative and came
	out looking like a very large number.  Instead I cheated and
	used an absolute time that translated into 10 minutes worth of
	clicks.

	I'd like to find out how to get a delta time to look like a
	negative ixp number, so that I can deal with it with the IXP
	routines.
}

status := $BINTIM('17-NOV-1858 00:10:00.0',delta_time_ixp.DATE); {same as above}
time_buffer := '                       ';			 {...}
status := $ASCTIM(,time_buffer,delta_time_ixp.DATE);
WRITELN('delta time	:	',time_buffer);
status := IXP$CVTXA(delta_time,ixp_value,length);
WRITELN('value		:	',value_str:length);

status := IXP$ADDXN(time_sample,delta_time,result_time);	{add the two}
IF NOT ODD(STATUS) THEN LIB$SIGNAL(STATUS);
time_buffer := '                       ';		
status := $ASCTIM(,time_buffer,result_time_ixp.DATE);	{and print the result}
WRITELN('result time	:	',time_buffer);
status := IXP$CVTXA(result_time,ixp_value,length);
WRITELN('value		:	',value_str:length);

END.


------
here is the sample output again, for convenience:

time sample	:	 7-DEC-1984 14:01:20.92
value		:	39779928809200000
delta time	:	17-NOV-1858 00:10:00.00
value		:	6000000000
result time	:	 7-DEC-1984 14:11:20.92
value		:	39779934809200000


Thanks, everyone for your help, especially Richard Kittell.

						-Jeff


177.6CHAOS::DICKENSFri Dec 07 1984 16:5842
I made the following changes to a copy of my test program to illustrate
the problem.  The ixp variable delta_time now gets a real delta time assigned
to it, and it can't handle it.

************
File SYS$SYSDEVICE:[DICKENS]TESTIXP.PAS;20
  171   status := $BINTIM('17-NOV-1858 00:10:00.0',delta_time_ixp.DATE); {same as above}
  172   time_buffer := '                       ';			 {...}
******
File SYS$SYSDEVICE:[DICKENS]TESTIXP1.PAS;2
  171   status := $BINTIM('0 00:10:00.00',delta_time_ixp.DATE); {same as above}
  172   time_buffer := '                       ';			 {...}
************

Number of difference sections found: 1
Number of difference records found: 1

DIFFERENCES /IGNORE=()/MERGED=1/OUTPUT=SYS$SYSDEVICE:[DICKENS]TESTIXP1.DIF;1-
    SYS$SYSDEVICE:[DICKENS]TESTIXP.PAS;20-
    SYS$SYSDEVICE:[DICKENS]TESTIXP1.PAS;2


Here is the output from the modified program:

time sample	:	 7-DEC-1984 16:45:51.92
value		:	39780027519200000
delta time	:	   0 00:10:00.00       
value		:	18446744067709551616
----
At this point the program bombs out when IXP$ADDXN returns SS$INTOVF, 
an integer overflow error trying to add the two values above inside
a quadword.  I couldn't figure out how to redirect the error output,
but it didn't show much anyway.

The value of 'delta time` above should equal -600000000 or something
like that, not a 20 digit positive integer.  Does anyone see what
I'm doing wrong ?

Thanks again,
					-Jeff


177.7CHAOS::DICKENSMon Dec 10 1984 15:5410
I now understand the problem.  

The data part of the IXP XN is just the magnitude of the number, and the
system service $BINTIM is depositing a twos complement negative number
in that quadword when I call it with a delta time.

Is there any way I can convert this number to it's absolute value, so that
IXP will see the real magnitude of the number ?  Then I can fix the sign 
bit in the XN header to get the correct value.

177.8CHAOS::DICKENSWed Dec 19 1984 14:1263
Problem solved.  Thanks for all your help. :-)

I seems I was overlooking the obvious.  I was reading the
run time library reference manual on the RTL routines LIB$ADDX and
LIB$SUBX and found that they take the longword address of an array
of longwords as arguments.  The default length of the arrays is 2,
a quad.  I took a lucky guess that the internal representation of
an array of two longwords is the same as the record definition for
$QUAD that I got from STARLET.  It seems it was.  Here's a demo
program:

************************************************************************

[INHERIT ('SYS$LIBRARY:STARLET')]

PROGRAM TEST_TIME(input,output);

TYPE
	$QUAD	= [QUAD,UNSAFE] RECORD
	L0:UNSIGNED; L1:INTEGER; END;

	timbuf_type	=	PACKED ARRAY [1..23] OF CHAR;

VAR
	time_sample, time_sample1, sum	:	$QUAD;
	
	status		: 	INTEGER;
	time_buffer	:	timbuf_type;

FUNCTION LIB$ADDX(a,b,s : $QUAD ):INTEGER;EXTERNAL;

FUNCTION LIB$SUBX(a,b,s : $QUAD ):INTEGER;EXTERNAL;

BEGIN
status := $GETTIM(time_sample);
status := $ASCTIM(,time_buffer,time_sample);
WRITELN(time_buffer);

status := $BINTIM('0 00:10:00.00',time_sample1);
time_buffer := '                       ';
status := $ASCTIM(,time_buffer,time_sample1);
WRITELN(time_buffer);

status := LIB$SUBX(time_sample,time_sample1,sum);
status := $ASCTIM(,time_buffer,sum);
WRITELN(time_buffer);


END.


************************************************************************

Here's the output:

18-DEC-1984 22:06:56.30
   0 00:10:00.00       
18-DEC-1984 22:16:56.30


************************************************************************