Boletín Pascal #9
INDICE
1. UNAS PALABRAS DEL EDITOR
2. PROGRAMACION DE BASES DE DATOS EN CODIGO (III)
* CONSULTAS DE ACCION
- UPDATE
- INSERT
- DELETE
* LENGUAJE DE DEFINICION DE DATOS (DATA DEFINITION LANGUAGE - DDL)
- CREATE TABLE
- ALTER TABLE
- DROP TABLE
- CREATE INDEX
- DROP INDEX
* SUBCONSULTAS
- EN LA CLAUSULA FROM
- EN LAS CLAUSULAS WHERE O HAVING
- Exists
- In
- COMO VALOR
3. ALGUNAS NOTAS ACERCA DE LA PROGRAMACION EN ENTORNOS DE RED
* BASES DE DATOS PARADOX
* MEJORANDO EL RENDIMIENTO
- ACTUALIZACIONES CACHEADAS
- COMPONENTES QUE CACHEAN
- RANGOS DE CLAVES
- PREPARAR CONSULTAS
- COMPACTAR TABLAS
- TABLAS LOCALES Y DATASETS CLIENTES
4. REDONDEANDO NUMEROS
5. ENLACES KYLIX
________________________________________________________________________
1. UNAS PALABRAS DEL EDITOR
Acerca del artículo "KYLIX FAQ (PREGUNTAS FRECUENTES)" de la edición
pasada, un suscriptor nos informó que la versión beta de Delphi para
Linux corre en un número selecto de distribuciones Linux y que los
ejecutables que produce requieren grades bibliotecas de tiempo de
ejecución. Nosotros realmente esperamos que la versión final corra en
todas las distros y que produzca ejecutables independientes, pero no
podemos asegurar nada pues toda la información proporcionada por
Borland acerca del proyecto Kylix no es oficial y está sujeta a
cambios hasta cerca de la fecha de lanzamiento, cuando se conozcan los
hechos reales.
Borland anunció el lugar y las fechas de la BorCon 2001. La XII
Conferencia Anual de Borland (Americas) tendrá lugar del 21 al 25 de
Julio del 2001 en Long Beach, California. Quienes deseen más
información podrán encontrarla aquí: http://www.borland.com/conf2001/
Hay un par de trucos nuevos en nuestra sección de trucos Delphi:
¿Cómo...
* Cambiar la resolución de la pantalla?
* Hacer que una aplicación se ejecute automáticamente cuando Windows
se inicie?
Saludos,
Ernesto De Spirito
eds2008 @ latiumsoftware.com
________________________________________________________________________
JfControls Lib. Multilenguaje. Multiapariencia. Skins. Privilegios. Más
de 40 componentes integrados y personalizables. Múltiples problemas de
programación resueltos. Administración centralizada de recursos. Para
Delphi 3-2006 y C++ Builder 3-6. http://www.jfactivesoft.com/spindex.htm
________________________________________________________________________
2. PROGRAMACION DE BASES DE DATOS EN CODIGO (III)
CONSULTAS DE ACCION
===================
UPDATE
------
UPDATE nomtabla SET campo1 = valor1 [, campo2 = valor2 [, ...]]
[WHERE condicion]
Esta sentencia SQL le permite modificar los valores de uno o más campos
en uno o más registros de una tabla.
En xBase:
USE custoly
REPLACE ALL Country WITH "USA" FOR Country = "U.S.A."
En SQL:
UPDATE custoly SET Country = "USA" WHERE Country = "U.S.A."
En Delphi:
procedure TForm1.Button1Click(Sender: TObject);
var
Query1: TQuery;
begin
Query1 := nil;
try
Query1 := TQuery.Create(nil);
Query1.DatabaseName := 'DBDEMOS';
Query1.SQL.Add('UPDATE custoly SET Country = "USA"');
Query1.SQL.Add('WHERE Country = "U.S.A."');
Query1.ExecSQL;
except
Query1.Free;
raise;
end;
Query1.Free;
end;
INSERT
------
INSERT INTO nomtabla (campo1 [, campo2 [, ...]])
VALUES (valor1 [, valor2 [, ...]])
INSERT INTO nomtabla (campo1 [, campo2 [, ...]])
SELECT ...
Esta sentencia SQL agrega un registro o registros a una tabla. El
siguiente ejemplo muestra como agregar un registro a una tabla:
En xBase:
USE custoly
APPEND BLANK
REPLACE Last_Name WITH "Doe", First_Name WITH "John", ;
EMail WITH "johndoe@nn.com"
En SQL:
INSERT INTO custoly (Last_Name, First_Name, EMail)
VALUES ("Doe", "John", "johndoe@nn.com");
En Delphi:
...
Query1.SQL.Add('INSERT INTO custoly (Last_Name, First_Name,');
Query1.SQL.Add(' EMail) VALUES ("Doe", "John", "johndoe@nn.com");');
Query1.ExecSQL;
...
El siguiente ejemplo muestra como agregar varios registros:
En xBase:
USE custoly
APPEND FROM custoly2 FOR Country = "USA" ;
FIELDS Last_Name, First_Name, EMail
En SQL:
INSERT INTO custoly (Last_Name, First_Name, EMail)
SELECT Last_Name, First_Name, EMail FROM custoly2
WHERE Country = "USA";
En Delphi:
...
Query1.SQL.Add('INSERT INTO custoly (Last_Name, First_Name, EMail)');
Query1.SQL.Add('SELECT Last_Name, First_Name, EMail FROM custoly2');
Query1.SQL.Add('WHERE Country = "USA";');
Query1.ExecSQL;
...
DELETE
------
DELETE FROM nomtabla [WHERE condicion]
Esta sentencia SQL borra uno o más registros de una tabla.
En xBase:
USE custoly
DELETE ALL FOR Country = "US"
En SQL:
DELETE FROM custoly WHERE Country = "US"
En Delphi:
...
Query1.SQL.Add('DELETE FROM custoly WHERE Country = "US"');
Query1.ExecSQL;
...
El siguiente ejemplo muestra como borrar todos los registros de una
tabla:
In xBase:
USE custoly
DELETE ALL
In SQL:
DELETE FROM custoly
LENGUAJE DE DEFINICION DE DATOS (DATA DEFINITION LANGUAGE - DDL)
================================================================
Local SQL soporta unas pocas sentencias DDL que permiten crear,
modificar y borrar tablas, así como crear y borrar índices.
CREATE TABLE
------------
CREATE TABLE nomtabla (campo1 tipo1 [(escala1 [,precision1])]
[, campo2 tipo2 [(escala2 [,precision2])] [, ...] ]
[, [CONSTRAINT restriccion]
PRIMARY KEY (campoclave1 [, campoclave2 [, ...]]) ] )
Esta sentencia SQL permite crear una tabla en una forma mucho más
simple que usando el método CreateTable que hemos introducido en una
edición pasada.
Ejemplo (SQL):
CREATE TABLE "Productos.DBF" (IDProducto SMALLINT,
Descripcion VARCHAR(25), Precio FLOAT(10,2),
PRIMARY KEY (IDProducto))
Ejemplo (Delphi):
...
Query1.SQL.Add('CREATE TABLE "Productos.DBF" (IDProducto SMALLINT,');
Query1.SQL.Add('Descripcion VARCHAR(25), Precio NUMERIC(10,2),');
Query1.SQL.Add('PRIMARY KEY (IDProducto))');
Query1.ExecSQL;
...
ALTER TABLE
-----------
ALTER TABLE nomtabla { DROP [COLUMN] campo1 | ADD [COLUMN] campo1
type1 [(escala1 [,precision1])] } [, { DROP [COLUMN] campo2 | ADD
[COLUMN] campo2 type2 [(escala2 [,precision2])] } [,...] ]
Esta sentencia SQL permite añadir y/o remover columnas (campos) de una
tabla. Por ejemplo:
ALTER TABLE "Productos.DBF" ADD Costo NUMERIC(10,2),
ADD Stock INTEGER
ALTER TABLE "Productos.DBF" DROP Stock, ADD EnStock FLOAT(6,1)
En Delphi:
...
Query1.SQL.Add('ALTER TABLE "Productos.DBF" ADD Costo NUMERIC(10,2),');
Query1.SQL.Add('ADD Stock INTEGER');
Query1.ExecSQL;
Query1.SQL.Clear;
Query1.SQL.Add('ALTER TABLE "Productos.DBF" DROP Stock,');
Query1.SQL.Add('ADD EnStock FLOAT(6,1)');
Query1.ExecSQL;
...
DROP TABLE
----------
DROP TABLE nomtabla
Esta sentencia SQL borra una tabla.
Ejemplo:
...
Query1.SQL.Text := 'DROP TABLE "Productos.DBF"';
Query1.ExecSQL;
...
CREATE INDEX
------------
CREATE [UNIQUE] [ASC | DESC] INDEX nomindice ON nomtabla
(campoclave1 [, campoclave2 [,...]])
Esta sentencia SQL crea un índice en la tabla especificada. Por ejemplo:
En xBase:
USE vendors
INDEX ON VendorName TO PorNombre
En SQL:
CREATE INDEX PorNombre ON vendors (VendorName)
En Delphi:
...
Query1.SQL.Text := 'CREATE INDEX PorNombre ON vendors (VendorName)';
Query1.ExecSQL;
...
DROP INDEX
----------
DROP INDEX nomtabla.nomindice
Esta sentencia SQL borra un índice de la tabla especificada. Para borrar
la clave primaria tiene que escribir PRIMARY en lugar del nombre del
índice.
Ejemplo:
...
Query1.SQL.Text := 'DROP INDEX vendors.PorNombre';
Query1.ExecSQL;
...
SUBCONSULTAS
============
Una subconsulta es una consulta de selección dentro de otra consulta.
Las subconsultas se encierran entre paréntesis. Hay varios lugares donde
se puede usar una consulta...
EN LA CLAUSULA FROM
-------------------
La mayoría de los motores SQL permiten que una subconsulta sea usada
como una tabla en la cláusula FROM, pero Local SQL no se encuentra entre
ellos. Por ejemplo, esto no funcionaría:
SELECT Company, OrderNo, ItemsTotal
FROM
(SELECT OrderNo, CustNo, ItemsTotal FROM Orders
WHERE ItemsTotal > 50000) Ord
INNER JOIN Customer ON Ord.CustNo = Customer.CustNo
WHERE Country = "US"
En el caso del ejemplo, la consulta puede modificarse para obtener el
resultado deseado sin usar subconsultas:
SELECT Company, OrderNo, ItemsTotal
FROM Orders INNER JOIN Customer ON Orders.CustNo = Customer.CustNo
WHERE Country = "US" AND ItemsTotal > 50000
Cuando esto no es posible, la solución es:
1) Crear una tabla temporal:
CREATE TABLE tmp (OrderNo NUMERIC(8),
CustNo NUMERIC(8), ItemsTotal MONEY);
2) Hacer que contenga los resultados de la que era la subconsulta:
INSERT INTO tmp (OrderNo, CustNo, ItemsTotal)
SELECT OrderNo, CustNo, ItemsTotal
FROM Orders WHERE ItemsTotal > 50000;
3) Usa esta tabla temporal en la consulta original:
SELECT Company, OrderNo, ItemsTotal
FROM tmp Orders INNER JOIN Customer ON Orders.CustNo = Customer.CustNo
WHERE Country = "US"
4) Borrar la tabla temporal cuando ya no se la necesite:
DROP TABLE tmp
EN LAS CLAUSULAS WHERE O HAVING
-------------------------------
Una subconsulta puede ser parte de una condición usando diferentes
"predicados" (operadores). Estas subconsultas pueden usar valores
provenientes de la consulta dentro de la cual se encuentra y en este
caso son procesadas por cada registro de esa consulta.
Exists
------
EXISTS subconsulta
Este predicado devuelve True si la subconsulta devuelve al menos una
fila. Por ejemplo, la siguiente consulta devolverá los nombres de todos
los empleados que no hicieron ventas entre 1990 y 1994:
SELECT LastName, FirstName FROM employee
WHERE NOT EXISTS (SELECT OrderNo FROM orders WHERE
orders.EmpNo = employee.EmpNo AND
EXTRACT(YEAR FROM SaleDate) BETWEEN 1990 AND 1994)
In
--
valor IN (conjunto)
Este predicado devuelve True si el valor se encuentra en un conjunto.
Dicho conjunto puede ser una lista de valores (por ejemplo "CA", "FL",
VA") o una subconsulta que devuelva 0, 1 o más registros. Para invertir
la condición puede usar NOT IN.
El siguiente ejemplo devolvería los clientes de Sudamérica:
SELECT CustNo, Company, Country FROM customer
WHERE Country IN (SELECT Name FROM Country
WHERE Continent = "South America")
COMO VALOR
----------
En general, puede usar una subconsulta en cualquier otra situación donde
puede usar un simple valor. La limitación es que la subconsulta debe
devolver una sola fila y sólo el primer campo es usado (otros motores
SQL no limitan la cantidad de filas).
Por ejemplo, puede usar una subconsulta para calcular el valor de un
campo:
SELECT (SELECT SUM(Qty) FROM Items
WHERE OrderNo = 1004 GROUP BY OrderNo) AS Qty1004,
(SELECT SUM(Qty) FROM Items
WHERE OrderNo = 1005 GROUP BY OrderNo) AS Qty1005
FROM Customer WHERE CustNo = 1221
No usamos el cliente #1221 en la consulta, pero es un truco para
producir un solo registro en el resultado (otros motores SQL permiten
la omisión de la cláusula FROM para el mismo propósito). El resultado
sería:
Qty1004 Qty1005
------- -------
33 21
Para dar otro ejemplo, la siguiente consulta devuelve todas las órdenes
cuyos montos están por sobre el promedio:
SELECT OrderNo, ItemsTotal FROM orders
WHERE ItemsTotal > (SELECT AVG(ItemsTotal) FROM orders)
El código fuente completo de los ejemplos de este boletín está
disponible aquí:
http://www.latiumsoftware.com/es/file.php?id=p09
________________________________________________________________________
3. ALGUNAS NOTAS ACERCA DE LA PROGRAMACION EN ENTORNOS DE RED
BASES DE DATOS PARADOX
======================
Todas las aplicaciones que acceden tablas de una misma base de datos
Paradox deben usar el mismo archivo PDOXUSRS.NET. El bloqueo de
registros y otras características dependen de esto. No usar el mismo
archivo PDOXUSRS.NET puede resultar en datos corruptos y en pérdida de
datos.
El programa de instalación instala el archivo PDOXUSRS.NET en el direc-
torio raíz del primer disco duro de cada computadora donde lo corra
("C:\"), y establece la configuración NET DIR en su archivo IDAPI.CFG
en "C:\". Por consiguiente, de modo predeterminado, todas las aplica-
ciones de una misma estación de trabajo (EDT) comparten el mismo archivo
PDOXUSRS.NET, pero no todas las aplicaciones corriendo desde la red!
Hay dos formas de corregir esto. Una forma es cambiar el archivo
IDAPI.CFG en cada EDT:
1) Ejecute el BDE Administrator
2) En el menú "Object" elija "Open configuration..."
3) Abra el archivo IDAPI.CFG
4) En la solapa "Configuration" vaya a Configuration/Drivers/Native/
Paradox
5) Cambie la entrada NET DIR para apuntar a la ubicación del archivo
PDOXUSRS.NET compartido. Este puede ser por ejemplo F:\ en una EDT
y E:\ en otra, dependiendo de como esté configurado el mapeo de
unidades en cada EDT. Para evitar la dependencia en el mapeo de
unidades y usar un nombre uniforme en todas las EDTs puede usar
el camino de red \\MAQUINA\RECURSO\[CAMINO\], donde MAQUINA es el
nombre del servidor donde está localizado el archivo, RECURSO es el
nombre del recurso compartido (un directorio) y opcionalmente
CAMINO es el camino del subdirectorio donde está ubicado el archivo
PDOXUSRS.NET.
Si el archivo está localizado en C:\TODOS\BASEDATOS\PDOXUSRS.NET
por ejemplo, en un servidor llamado "SERVIDOR" que comparte el
directorio C:\TODOS bajo el nombre "COMPARTIDO", entonces el NET
DIR en todas las EDT (incluyendo el servidor) debería ser
\\SERVIDOR\COMPARTIDO\BASEDATOS\
6) Guardar los cambios (Object / Save As configuration).
La otra forma de hacerlo es establecer la propiedad NetFileDir del
objeto Session de sus aplicaciones antes de abrir cualquier tabla o
consulta. Por ejemplo:
Session.NetFileDir := '\\SERVIDOR\COMPARTIDO\BASEDATOS\';
MEJORANDO EL RENDIMIENTO
========================
La BDE tiene problemas serios en cuanto a rendimiento en una red, y esta
es una de las razones por las cuales hay varios reemplazos de la BDE
dando vuelta:
* BDE Alternatives Guide
http://bdealternatives.com/
No es mucho lo que se puede hacer para mejorar el rendimiento de la BDE,
pero puede intentar algunos de los siguientes consejos para ver si
ayudan.
ACTUALIZACIONES CACHEADAS
-------------------------
Las actualizaciones cacheadas (cached updates) aparentemente no sólo
cachea las actualizaciones a una tabla, sino que también cachea los
registros leídos de la tabla. El problema es que hace las cosas más
complicadas y tiene algunas desventajas... Puede encontrar información
sobre actualizaciones cacheadas en la ayuda de Delphi:
Developing Database Applications
Working with cached updates
COMPONENTES QUE CACHEAN
-----------------------
Si busca en la Internet debe poder encontrar reemplazos para algunos
componentes de acceso a datos (como TTable y TQuery) y algunos controles
de datos (como TDBGrid, TDBLookupListBox y TDBLookupComboBox) que
realizan algo de cacheo para brindar un mejor rendimiento. Estos
componentes habitualmente no son freeware, pero le sugerimos que los
pruebe porque bien pueden valer su costo de registración.
RANGOS DE CLAVES
----------------
Los rangos de claves son por lejos más veloces que los filtros. Debe
aplicar rangos de claves en vez de filtros cuando sea posible para
reducir la cantidad de registros y luego si es necesario usar filtros
para obtener los registros que desee. Por ejemplo, si su condición de
filtro es como esta:
CustNo = X AND SaleDate > D1 AND SaleDate < D2 AND Code = Y
y tiene un índice por CustNo y SaleDate, entonces debería aplicar un
rango de claves ( SetRange([X,D1], [X,D2]); ) y usar un filtro con la
condición Code = Y.
PREPARAR CONSULTAS
------------------
Si usa una consulta más o menos frecuentemente puede prepararla (con el
método Prepare) para hacer que la BDE la compile y la guarde compilada
hasta que la libere (con el método Unprepare). Cuando una consulta está
preparada se ejecuta más rápido.
COMPACTAR TABLAS
----------------
Los registros borrados ocupan espacio, y cuando el borrado de registros
sucede más o menos a menudo, tarde o temprano los registros borrados
pasan a ser más del 50% del total del número de registros. El espacio
no utilizado no es en sí el problema, sino que se desperdicia ancho de
banda de la red transfiriendo registros que no se usan. Por esta razón
debe compactar las tablas removiendo los registros borrados cada cierto
tiempo. El ejemplo de DbiPackTable en el archivo de ayuda muestra
claramente como hacer esto.
TABLAS LOCALES Y DATASETS CLIENTES
----------------------------------
Tal vez la mejor y más simple forma de reducir el tráfico de la red y
mejorar el rendimiento sea teniendo una copia local de algunas tablas
de la base de datos y usar esas copias locales para leer registros.
Cuando realice una actualización (ABC), debe actualizar tanto la tabla
local como la tabla en el servidor. Esto asegura que la tabla del
servidor siempre esté actualizada.
El problema es que los cambios hechos por otros usuarios no serán
visibles en su aplicación hasta que "refresque" las tablas locales
(copiándolas nuevamente desde el servidor), y por lo tanto esta técnica
sólo debe usarse con tablas para las cuales es bastante improbable que
dos o más usuarios vayan a agregar o editar el mismo registro con datos
diferentes.
Debe refrescar las tablas locales cada tanto: cuando Windows inicia,
cuando su aplicación inicia, una vez al día, una vez a la semana, cuando
el usuario presione un botón Refrescar, o cuando sea... Dependerá de la
tabla, y puede juzgar caso por caso: algunas tablas pueden requerir
refrescos más frecuentes que otras, y debe sacar ventaja de este hecho
para no refrescar las tablas con mayor frecuencia que la necesaria.
Si usa tablas Paradox, tiene que usar una sesión diferente para las
tablas locales con su propio NetFileDir conteniendo la ubicación del
archivo PDOXUSRS.NET local.
Si tiene la Edición Empresarial de Delphi, puede usar Datasets Clientes
(Client Datasets) para algunas de las tablas locales. Los Datasets
Clientes guardan los registros en memoria (así que no debería usarlos
con grandes tablas) y son muy rápidos y potentes.
________________________________________________________________________
4. REDONDEANDO NUMEROS
La función Round que viene con Delphi realiza lo que se llama "redondeo
bancario", significando que un número con una parte fraccional de 0.5 se
redondea a veces para arriba y otras para abajo, siempre hacia el número
par más cercano. Es decir que por ejemplo Round(3.5) devuelve 4 mientras
que Round(2.5) devuelve 2.
Aquí va un conjunto de funciones para redondear números, incluyendo
RoundN que redondea un número "normalmente" (es decir que RoundN(3.5)
devuelve 4 y RoundN(2.5) devuelve 3).
function Sgn(X: Extended): Integer;
// Devuelve -1, 0 o 1 de acuerdo al signo del argumento
begin
if X < 0 then
Result := -1
else if X = 0 then
Result := 0
else
Result := 1;
end;
function RoundUp(X: Extended): Extended;
// Devuelve el primer entero mayor que o
// igual al número dado en valor absoluto
// (se preserva el signo).
// RoundUp(3.3) = 4 RoundUp(-3.3) = -4
begin
Result := Int(X) + Sgn(Frac(X));
end;
function RoundDn(X: Extended): Extended;
// Devuelve el primer entero menor que o
// igual al número dado en valor absoluto
// (se preserva el signo).
// RoundDn(3.7) = 3 RoundDn(-3.7) = -3
begin
Result := Int(X);
end;
function RoundN(X: Extended): Extended;
// Redondea un numero "normalmente": si la parte fraccional
// es >= 0.5 el número se redondea para arriba (ver RoundUp).
// En caso contrario, si la parte fraccional es < 0.5, el
// número se redondea para abajo (ver RoundDn).
// RoundN(3.5) = 4 RoundN(-3.5) = -4
// RoundN(3.1) = 3 RoundN(-3.1) = -3
begin
(*
if Abs(Frac(X)) >= 0.5 then
Result := RoundUp(X)
else
Result := RoundDn(X);
*)
Result := Int(X) + Int(Frac(X) * 2);
end;
function Fix(X: Extended): Extended;
// Devuelve el primer entero menor
// o igual al número dado.
// Int(3.7) = 3 Int(-3.7) = -3
// Fix(3.7) = 3 Fix(-3.1) = -4
begin
if (X >= 0) or (Frac(X) = 0) then
Result := Int(X)
else
Result := Int(X) - 1;
end;
function RoundDnX(X: Extended): Extended;
// Devuelve el primer entero menor
// o igual al número dado.
// RoundDnX(3.7) = 3 RoundDnX(-3.7) = -3
// RoundDnX(3.7) = 3 RoundDnX(-3.1) = -4
begin
Result := Fix(X);
end;
function RoundUpX(X: Extended): Extended;
// Devuelve el primer entero mayor
// o igual al número dado.
// RoundUpX(3.1) = 4 RoundUpX(-3.7) = -3
begin
Result := Fix(X) + Abs(Sgn(Frac(X)))
end;
function RoundX(X: Extended): Extended;
// Redondea un numero "normalmente", pero
// tenindo en cuenta el signo.
// Si la parte fraccional es >= 0.5 el número se
// redondea para arriba (ver RoundUpX).
// En caso contrario, si la parte fraccional es < 0.5,
// el número se redondea para abajo (ver RoundDnX).
// RoundX(3.5) = 4 RoundX(-3.5) = -3
begin
(*
if Abs(Frac(X)) >= 0.5 then
Result := RoundUpX(X)
else
Result := RoundDnX(X);
*)
Result := Fix(X + 0.5);
end;
Estas funciones que acabamos de presentar siempre redondean el último
dígito entero, pero a veces necesitamos redondear por ejemplo la segunda
cifra decimal o en miles, millones y billones. Puede sobrecargar la
función RoundN con esta versión que toma un parámetro adicional para
indicar el dígito que se redondeará:
function RoundN(x: Extended; d: Integer): Extended;
// RoundN(123.456, 0) = 123.00
// RoundN(123.456, 2) = 123.46
// RoundN(123456, -3) = 123000
const
t: array [0..12] of int64 = (1, 10, 100, 1000, 10000, 100000,
1000000, 10000000, 100000000, 1000000000, 10000000000,
100000000000, 1000000000000);
begin
if Abs(d) > 12 then
raise ERangeError.Create('RoundN: valor debe estar en -12..12');
if d = 0 then
Result := Int(x) + Int(Frac(x) * 2)
else if d > 0 then begin
x := x * t[d];
Result := (Int(x) + Int(Frac(x) * 2)) / t[d];
end else begin // d < 0
x := x / t[-d];
Result := (Int(x) + Int(Frac(x) * 2)) * t[-d];
end;
end;
________________________________________________________________________
5. ENLACES
EN ESPAÑOL
==========
* Diego Muñoz
Programador Freelance en Delphi. Artículos, trucos y Mi Sistema
http://www.crosswinds.net/~diegodjm
KYLIX (En Inglés)
=================
http://www.borland.com/kylix/
http://slashdot.org/search.pl?query=kylix
http://linuxtoday.com/search.php3?query=kylix
http://www.drbob42.com/kylix/index.htm
http://www.delphi4linux.org/
http://www.oreilly.com/news/kylix_0400.html
http://www.oreilly.com/news/kylix_0800.html
http://www.delphi32.com/info_facts/kylix/index.asp
http://www.hadp.org/kylix.htm
http://www.pinpub.com/delphi/kylix1.htm
http://www.pinpub.com/delphi/kylix2.htm
http://www.linuxworld.com/linuxworld/lw-2000-07/lw-07-newslint_1.html
http://www.delphizine.com/opinion/2000/10/di200010fn_o/di200010fn_o.asp
http://www.elists.org/mailman/listinfo/kylix
http://www.delphi-jedi.org/Jedi:VOYJEDIX:646728132
http://209.35.83.42/bbug/kylix/main.htm
http://www.delphizine.com/search/results.asp?QU=kylix
http://delphi.about.com/compute/delphi/library/weekly/aa031400a.htm
________________________________________________________________________
Si no has recibido el archivo con el código fuente completo de los
ejemplos que se presentan en este boletín, puedes descargarlo de la
siguiente dirección: http://www.latiumsoftware.com/es/file.php?id=p09
________________________________________________________________________
Página principal: http://www.latiumsoftware.com/es/pascal/index.php
Página del grupo: http://espanol.groups.yahoo.com/group/boletin-pascal/
Para suscribirse / apuntarse: boletin-pascal-subscribe@gruposyahoo.com
Para cancelar / removerse: boletin-pascal-unsubscribe@gruposyahoo.com
Para reportar problemas con la suscripción: eds2008 @ latiumsoftware.com
________________________________________________________________________
Este boletín se provee "TAL Y COMO ESTA", sin garantía de ninguna clase.
Su uso implica la aceptación de nuestros términos de licencia y de la
ausencia de garantía que puedes leer en nuestro sitio web. Allí también
encontrarás una nota sobre marcas registradas. Te animamos a que redis-
tribuyas este boletín, siempre y cuando lo hagas en forma completa
(incluyendo la información de copyright), sin modificaciones y de manera
gratuita. Los artículos son copyright de sus respectivos autores y se
reproducen aquí con el permiso de los mismos.
________________________________________________________________________
Latium Software http://www.latiumsoftware.com/es/index.php
Copyright (c) 2000 por Ernesto De Spirito. Todos los derechos reservados
________________________________________________________________________
|