Next: , Previous: , Up: objects   [Index]


13.15 Ratnum objects

Ratnums are exact rational numbers, having a fixnum or bignum as numerator and a fixnum or bignum as denominator; the numerator is always non–zero; the denominator is always strictly positive, the sign of a ratnum is the sign of the numerator.

A ratnum is a fixed length memory block referenced by machine words tagged as vectors. The first machine word of a ratnum block is tagged has ratnum in its least significant bits and it has the most significant bits set to zero.

|------------------------|-------------| reference to ratnum
      heap pointer         vector tag

|------------------------|-------------| ratnum first word
   all set to zero         ratnum tag

A ratnum memory block is 4 words wide; a reference to the numerator is stored in the second word and a reference to the denominator is stored in the third word:

   1st word     2nd word     3rd word     4th word
|------------|------------|------------|------------|
 tagged word   numerator   denominator     unused

Basic operations

Ratnums are allocated on the Scheme heap as follows:

ikpcb_t * pcb   = ik_the_pcb();
ikptr_t   s_rn;

s_rn = ik_safe_alloc(pcb, ratnum_size) | vector_tag;
IK_RATNUM_TAG(s_rn) = ratnum_tag;

after allocation we must always initialise the numerator and denominator fields to some correct value before running the next garbage collection. A full allocation and initialisation is as follows:

ikpcb_t * pcb   = ik_the_pcb();
ikptr_t   s_num = the_numerator;
ikptr_t   s_den = the_denominator;
ikptr_t   s_rn;

pcb->root9 = &s_num;
pcb->root8 = &s_den;
{
  s_rn = ik_safe_alloc(pcb, ratnum_size) | vector_tag;
}
pcb->root8 = NULL;
pcb->root9 = NULL;

IK_RATNUM_TAG(s_rn) = ratnum_tag;
IK_RATNUM_NUM(s_rn) = s_num;
IK_RATNUM_DEN(s_rn) = s_den;

notice that, as in this example, when a new ratnum object is allocated after the allocation of the numerator and denominator objects: we do not need to call ik_signal_dirt_in_page_of_pointer() for s_rn because the ratnum is on the Scheme heap’s nursery, so it will for sure be scanned at the next garbage collection.

If we allocate the ratnum object first, then the numerator and denominator objects, we want to follow this pattern:

ikpcb_t *  pcb  = ik_the_pcb();
iksword_t  num  = the_numerator;
iksword_t  den  = the_denominator;
ikptr_t    s_rn = ik_safe_alloc(pcb, ratnum_size) | vector_tag;
IK_RATNUM_TAG(s_rn) = ratnum_tag;

pcb->root9 = &s_rn;
{
  IK_ASS(IK_RATNUM_NUM(s_rn), \
     ika_integer_from_sword(pcb, num));
  IK_SIGNAL_DIRT(pcb, IK_RATNUM_NUM_PTR(s_rn));

  IK_ASS(IK_RATNUM_DEN(s_rn), \
     ika_integer_from_sword(pcb, den));
  IK_SIGNAL_DIRT(pcb, IK_RATNUM_DEN_PTR(s_rn));
}
pcb->root9 = NULL;

To set or retrieve the numerator and denominator we do:

ikptr_t  s_rn = the_ratnum;
ikptr_t  s_num;
ikptr_t  s_den;

s_num = IK_RATNUM_NUM(s_rn);
s_den = IK_RATNUM_DEN(s_rn);

IK_RATNUM_NUM(s_rn) = s_num;
IK_SIGNAL_DIRT(pcb, IK_RATNUM_NUM_PTR(s_rn));

IK_RATNUM_DEN(s_rn) = s_den;
IK_SIGNAL_DIRT(pcb, IK_RATNUM_DEN_PTR(s_rn));
Preprocessor Symbol: ratnum_size

The number of bytes to allocate to hold a ratnum memory block.

Preprocessor Symbol: ratnum_tag

The tag of ikptr_t values used as first words in ratnum memory blocks.

Preprocessor Symbol: disp_ratnum_tag

Displacement of secondary tag word. The number of bytes to add to an untagged pointer to ratnum to get the pointer to the first byte in the word holding the ratnum tag.

Preprocessor Symbol: disp_ratnum_num
Preprocessor Symbol: disp_ratnum_den

Displacements of numerator and denominator. The number of bytes to add to an untagged pointer to ratnum to get the pointer to the first byte of the reference to the numerator or denominator.

Preprocessor Symbol: off_ratnum_tag

An integer to add to add to a tagged ikptr_t pointer to ratnum to get the pointer to the first byte in the word holding the ratnum tag.

Preprocessor Symbol: off_ratnum_num
Preprocessor Symbol: off_ratnum_den

An integer to add to a tagged ikptr_t pointer to ratnum to get the pointer to the first byte of the words referencing the numerator or denominator.

Convenience preprocessor macros

Preprocessor Macro: int IK_IS_RATNUM (ikptr_t obj)

Evaluate to true if obj is a ratnum object; otherwise evaluate to false.

Preprocessor Macro: ikptr_t IK_RATNUM_TAG (ikptr_t X)

Evaluate to the location of the first word in the ratnum memory block; X must be a tagged pointer to a ratnum object. A use of this macro can appear both as operand and as left–side of an assignment.

Preprocessor Macro: ikptr_t IK_RATNUM_NUM (ikptr_t X)
Preprocessor Macro: ikptr_t IK_RATNUM_DEN (ikptr_t X)

Evaluate to the location of the numerator or denominator in the ratnum memory block; X must be a tagged pointer to a ratnum object. A use of these macros can appear both as operand and as left–side of an assignment:

ikptr_t  s_rn  = the_ratnum;
ikptr_t  s_num;
ikptr_t  s_den;

s_num = IK_RATNUM_NUM(s_rn);
s_den = IK_RATNUM_NUM(s_rn);

IK_RATNUM_NUM(s_rn) = s_num;
IK_SIGNAL_DIRT(pcb, IK_RATNUM_NUM_PTR(s_rn));

IK_RATNUM_DEN(s_rn) = s_den;
IK_SIGNAL_DIRT(pcb, IK_RATNUM_DEN_PTR(s_rn));
Preprocessor Macro: ikptr_t * IK_RATNUM_NUM_PTR (ikptr_t X)
Preprocessor Macro: ikptr_t * IK_RATNUM_DEN_PTR (ikptr_t X)

Evaluate to a pointer to the location of the numerator and denominator objects in X, which must be a tagged pointer to a ratnum object. These macros are useful to build the second argument for calls to ik_signal_dirt_in_page_of_pointer().

Operations on ratnums

Function: int ik_is_ratnum (ikptr_t obj)

Return true if obj is a ratnum object.

Function: ikptr_t ika_ratnum_alloc_no_init (ikpcb_t * pcb)

Allocate a new ratnum object using ik_safe_alloc() and return a tagged reference to it. The fields are left uninitialised.

Function: ikptr_t ika_ratnum_alloc_and_init (ikpcb_t * pcb)

Allocate a new ratnum object using ik_safe_alloc() and return a tagged reference to it. Both the fields are set to the fixnum zero.


Next: , Previous: , Up: objects   [Index]