Foros Club Delphi

Foros Club Delphi (https://www.clubdelphi.com/foros/index.php)
-   Varios (https://www.clubdelphi.com/foros/forumdisplay.php?f=11)
-   -   Obtener un número positivo o negativo. (https://www.clubdelphi.com/foros/showthread.php?t=72733)

marcoszorrilla 09-03-2011 13:24:42

Obtener un número positivo o negativo.
 
En una tabla guardo abonos y cargos los abonos tienen que ser negativos y los cargos positivos. El objeto es que al facturar cargue o abone dichas cantidades.

El propósito es, independientemente de la buena voluntad del usuario que los bultos y unidades sean positivas o negativas dependiendo de lo explicado anteriormente.

Código Delphi [-]
//Empece así:
procedure TDmAbon.IBDtsAbonBeforePost(DataSet: TDataSet);
begin
 if Es_Abono = True then
 begin
 DmAbon.IBDtsAbonBULTOS.AsFloat  :=Sqr(Power(DmAbon.IBDtsAbonBULTOS.Value,2))*-1;
 DmAbon.IBDtsAbonUNIDADES.AsFloat:=Sqr(Power(DmAbon.IBDtsAbonUNIDADES.Value,2))*-1;
 end
 else
 begin
 DmAbon.IBDtsAbonBULTOS.AsFloat  :=Sqr(Power(DmAbon.IBDtsAbonBULTOS.Value,2));
 DmAbon.IBDtsAbonUNIDADES.AsFloat:=Sqr(Power(DmAbon.IBDtsAbonUNIDADES.Value,2));
 end;

end;


//Lo remedé así:

procedure TDmAbon.IBDtsAbonBeforePost(DataSet: TDataSet);
begin
 if Es_Abono = True then
 begin
 DmAbon.IBDtsAbonBULTOS.AsInteger  :=ABS(DmAbon.IBDtsAbonBULTOS.Value)*-1;
 DmAbon.IBDtsAbonUNIDADES.AsInteger:=ABS(DmAbon.IBDtsAbonUNIDADES.Value)*-1;
 end
 else
 begin
 DmAbon.IBDtsAbonBULTOS.AsInteger  :=ABS(DmAbon.IBDtsAbonBULTOS.Value);
 DmAbon.IBDtsAbonUNIDADES.AsInteger:=ABS(DmAbon.IBDtsAbonUNIDADES.Value);
 end;

end;

Alguna otra idea?

Un Saludo.

Ñuño Martínez 09-03-2011 13:37:24

La solución de calcular el valor absoluto y luego multiplicar o no por -1 me parece la más cómoda. No sé si sería más eficiente comprobar los valores:
Código Delphi [-]
  IF ValorPositivo < 0 THEN
    ValorPositivo := ValorPositivo * (-1);
  IF ValorNegativo > 0 THEN
    ValorNegativo := ValorNegativo * (-1);
Vamos, que no sé cómo está implementado "ABS", porque si el compilador la expande como hace, por ejemplo, con INC y DEC entonces creo que da lo mismo, casi.

marcoszorrilla 09-03-2011 14:49:30

Gracias Ñuño, creo que lo dejaré tal como está. Que conste que antes de hacer cosas como está pronuncio internamente "la polvora la inventaron los chinos...".

Un Saludo.

Delphius 09-03-2011 15:30:28

Hola,
Creo que lo más adecuado es irse por el valor absoluto. Supuestamente ya está optimizada esta función y debería hacer uso de la instrucción ABS y/o FABS en assembler que justamente lo único que hacen es alterar el campo de signo. ;)

La ventaja del uso del valor absoluto es que no interesa si se ingresa positivo o negativo... siempre se obtiene el "lado positivo" y lo que nos resta por hacer es multiplicarlo por -1 en caso de ser necesario (que es más que evidente que solo aplica para cuando se requiere de los negativos) y no se necesita de hacer evaluaciones previas, como la que sugiere Nuño. Añadir un IF equivale a añadir un V(G) = 2. Dos IFs, son V(G) = 4. A mi humilde ver, me parece algo exagerado contar con una V(G) de 4 sólo para generar positivos y/o negativos.

Cuanto mucho me podría preguntar si da lo mismo hacer:

Código Delphi [-]
Negativo := - Abs(Valor);

Que:

Código Delphi [-]
Negativo := Abs(Valor) * -1;

Saludos,

roman 09-03-2011 16:16:27

También podrías evitar el condicional:

Código Delphi [-]
DmAbon.IBDtsAbonBULTOS.AsInteger   := (2*Integer(EsAbono) - 1)*ABS(DmAbon.IBDtsAbonBULTOS.Value);
DmAbon.IBDtsAbonUNIDADES.AsInteger := (2*Integer(EsAbono) - 1)*ABS(DmAbon.IBDtsAbonUNIDADES.Value);

// Saludos

coso 09-03-2011 16:35:03

Hola,
tambien podrias asignar directamente el bit de paridad con un or (no recuerdo cual es) aunque supongo que es lo que debe hacer abs o algo bastante parecido.
Saludos.

Al González 09-03-2011 17:24:45

Yo también optaría por una solución como la de Román, dándole simetría aritmética al condicionante Boolean. Pero a esa variable le daría un significado positivo, es decir, la llamaría EsCargo (que de hecho es el sentido que adquiere el código de Román). :)

Saludos.

roman 09-03-2011 17:48:59

Cita:

Empezado por Al González (Mensaje 392988)
que de hecho es el sentido que adquiere el código de Román

Je, je. Me equivoqué. Sería así:

Código Delphi [-]
DmAbon.IBDtsAbonBULTOS.AsInteger   := (-2*Integer(EsAbono) + 1)*ABS(DmAbon.IBDtsAbonBULTOS.Value);
DmAbon.IBDtsAbonUNIDADES.AsInteger := (-2*Integer(EsAbono) + 1)*ABS(DmAbon.IBDtsAbonUNIDADES.Value);

Por otro lado, también podría optarse por crear disparadores before insert y before update para asegurar las signaturas correctas en la base.

// Saludos

marcoszorrilla 09-03-2011 19:52:46

Me gusta la solución de Román, gracias también al resto que me habeis dado pautas interesantes.

Decir que Es_Cargo es una variable de tipo Boolean que le paso desde el menú y que se analiza en el evento de apertura del formulario para saber cual de las dos opciones se está ejecutando.


Por otra parte como veis el código va en el evento:
Código Delphi [-]
procedure TDmAbon.IBDtsAbonBeforePost(DataSet: TDataSet);
begin
Para que cada vez que se ejecute algún cambio en los datos se actualice el valor.

Un Saludo.

Ñuño Martínez 09-03-2011 20:20:26

Cita:

Empezado por coso (Mensaje 392983)
Hola,
tambien podrias asignar directamente el bit de paridad con un or (no recuerdo cual es) aunque supongo que es lo que debe hacer abs o algo bastante parecido.
Saludos.

No exactamente. En las computadoras binarias modernas, para obtener el negativo de un entero hay calcular el su complemento binario, de esta forma:
Código Delphi [-]
FUNCTION Complemento (Valor: INTEGER): INTEGER;
BEGIN
  RESULT := (NOT Valor) + 1;
END;

Por ejemplo, para el -3:
Código:

Complemento ( 3) = NOT ( 3) + 1 = NOT (0011) + 0001 = 1100 + 0001 = 1101 = -3
Complemento (-3) = NOT (-3) + 1 = NOT (1101) + 0001 = 0010 + 0001 = 0011 =  3

Esto mantiene la coherencia matemática:
Código:

4 - 7 = 4 + (-7) = -3

0100 - 0111 = 0100 + 1001 = 1101

Incluso con el cero:
Código:

NOT (0) + 1 = NOT (0000) + 0001 = 1111 + 0001 = 0000

Delphius 09-03-2011 20:53:37

Hola,
A ver Nuño, la verdad es que me matas con tu explicación. Entiendo lo que dices, y pareciera ser bastante coherente. Pero que yo sepa hay un estándar en como se guardan los números. Este estándar establece un formato adecuado, y casualmente se destina un campo para indicar si el número es positivo o negativo, parecido al formato que se ha definido para los números flotantes. La diferencia respecto a éste es que no posee campos para exponentes sino un campo para el número en si:

Código:

+-+--- ... ---+
| |          |
+-+--- ... ---+

EDITO:
El estándar indica que los números negativos están expresados en complemento-2. Y resulta ser estos complementos SIEMPRE tienen un 1 en el campo destinado al signo. Las rutinas INVIERTEN este campo, y naturalmente deberá complementar el resto.

En donde si me corrijo es en haber dicho que ABS y FABS únicamente alterar el campo de signo. Pero vamos, que realizar el complemento-2 del número es una rutina más que normal para la máquina por lo que no deberíamos preocuparnos demasiado en bajarnos a estos niveles.

No nos deberíamos complicar demasiado... ya Abs() nos hace fácil la cosa.

Saludos,

coso 09-03-2011 22:41:25

Cierto, confundi el bit de paridad con el de signo, y no se bien bien si existe. Gracias por la aclaracion, Ñuño.

Ñuño Martínez 11-03-2011 09:58:20

Cita:

Empezado por Delphius (Mensaje 393032)
(...) Pero que yo sepa hay un estándar en como se guardan los números. (...)

Pues eso: el complemente binario o "complemento a dos" es la norma más usada en la representación de números binarios con signo. Para punto flotante se usa otro método cuya base matemática es algo más obscura.


La franja horaria es GMT +2. Ahora son las 20:08:39.

Powered by vBulletin® Version 3.6.8
Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
Traducción al castellano por el equipo de moderadores del Club Delphi