punto flotante de precisión extendida de 80 bits en OCaml


¿Hay una biblioteca OCaml para aprovechar el tipo de coma flotante de precisión extendida de 80 bits en las arquitecturas IA-32 y x86-64?

Sé acerca de los enlaces MPFR pero mi biblioteca ideal sería más ligero. Lo ideal sería aprovechar las instrucciones históricas de coma flotante.

Author: Pascal Cuoq, 2012-11-20

1 answers

La implementación de tal biblioteca es posible fuera del compilador, gracias al soporte ffi del lenguaje.

La biblioteca debe dividirse en dos partes: la parte de origen ocaml nativa y la parte de tiempo de ejecución C. la fuente OCaml debe contener la declaración de tipo de datos, así como la declaración de todas las funciones importadas. Por ejemplo, la operación add sería:

(** basic binary operations on long doubles *)
external add : t -> t -> t = "ml_float80_add"
external sub : t -> t -> t = "ml_float80_sub"
external mul : t -> t -> t = "ml_float80_mul"
external div : t -> t -> t = "ml_float80_div"

En el código C, la función ml_float80_add debe definirse, como se describe en la OCaml manual:

CAMLprim value ml_float80_add(value l, value r){
   float80 rlf = Float80_val(l);
   float80 rrf = Float80_val(r);
   float80 llf = rlf + rrf;
   value res = ml_float80_copy(llf);
   return res;
}

Aquí convertimos las representaciones OCaml value en tiempo de ejecución a valores nativos de C, usamos el operador binario en ellas y devolvemos un nuevo valor OCaml. la función ml_float80_copy hace la asignación de esa representación en tiempo de ejecución.

Asimismo, las implementaciones C de sub, mul y div las funciones deben definirse allí también. Uno puede notar la similitud en la firma y la implementación de estas funciones, y abstraerse a través del uso de C macros:

#define FLOAT80_BIN_OP(OPNAME,OP)                   \
  CAMLprim value ml_float80_##OPNAME(value l, value r){     \
    float80 rlf = Float80_val(l);                           \
    float80 rrf = Float80_val(r);                           \
    float80 llf = rlf OP rrf;                               \
    value res = ml_float80_copy(llf);           \
    return res;                     \
  }


FLOAT80_BIN_OP(add,+);
FLOAT80_BIN_OP(sub,-);
FLOAT80_BIN_OP(mul,*);
FLOAT80_BIN_OP(div,/);

El resto del módulo OCaml y C debe seguir.

Hay muchas posibilidades de cómo codificar el tipo C float80 en un valor OCaml. La opción más simple es usar una cadena, y almacenar en ella el raw long double.

type t = string

En el lado C, definimos las funciones para convertir un valor OCaml de ida y vuelta a un valor C:

#include <caml/mlvalues.h>
#include <caml/alloc.h>
#include <caml/misc.h>
#include <caml/memory.h>


#define FLOAT80_SIZE 10  /* 10 bytes */

typedef long double float80;

#define Float80_val(x) *((float80 *)String_val(x))

void float80_copy_str(char *r, const char *l){
   int i;
   for (i=0;i<FLOAT80_SIZE;i++)
      r[i] = l[i];
}

void store_float80_val(value v,float80 f){
   float80_copy_str(String_val(v), (const char *)&f);
}

CAMLprim value ml_float80_copy(value r, value l){
   float80_copy_str(String_val(r),String_val(l));
   return Val_unit;
}

Sin embargo, esa implementación no brinda soporte para las funciones de comparación polimórfica integradas en OCaml Pervasive.compare, y algunas otras características. El uso de esa función en el tipo float80 anterior engañará a la función de comparación para que crea que los valores son cadenas y haga una comparación lexicográfica de su contenido.

Soportar estas características especiales es bastante simple. Redefinimos el tipo OCaml como abstracto, y cambiamos el código C para crear y manejar estructuras personalizadas para nuestro float80:

#include <caml/mlvalues.h>
#include <caml/alloc.h>
#include <caml/misc.h>
#include <caml/memory.h>
#include <caml/custom.h>
#include <caml/intext.h>

typedef struct {
   struct custom_operations *ops;
   float80 v;  
} float80_s;

#define Float80_val(x) *((float80 *)Data_custom_val(x))

inline int comp(const float80 l, const float80 r){
   return l == r ? 0: (l < r ? -1: 1); 
}

static int float80_compare(value l, value r){
   const float80 rlf = Float80_val(l);
   const float80 rrf = Float80_val(r);
   const int llf = comp(rlf,rrf);
   return llf;
}

/* other features implementation here */

CAMLexport struct custom_operations float80_ops = {
  "float80", custom_finalize_default, float80_compare, float80_hash,
  float80_serialize, float80_deserialize, custom_compare_ext_default
};

CAMLprim value ml_float80_copy(long double ld){
  value res = caml_alloc_custom(&float80_ops, FLOAT80_SIZE, 0, 1);  
  Float80_val(res) = ld;
  return res;
}

Luego proponemos construir todo usando ocamlbuild y un pequeño bash script.

 3
Author: didierc,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-03-19 18:06:57