Foros Club Delphi

Foros Club Delphi (https://www.clubdelphi.com/foros/index.php)
-   OOP (https://www.clubdelphi.com/foros/forumdisplay.php?f=5)
-   -   Problema para generar vector a partir de maskedit y combobox (https://www.clubdelphi.com/foros/showthread.php?t=89210)

MoeHoward 16-10-2015 03:55:51

Problema para generar vector a partir de maskedit y combobox
 
Hola buen día, soy usuario nuevo en el foro y vengo a pedir ayuda y orientación para resolver un problema muy básico al generar un vector a partir de valores ingresados en dos maskedit y un combobox, soy principiante usando delphi espero su comprensión.

El objetivo del programa es generar un vector de rango 'n'. Esta 'n' está definida por el rango existente entre el MaskEdit1 y el MaskEdit2. Por ejemplo, si el maskedit1 tiene como texto '0' y el maskedit2 tiene como texto '10', el rango será 10, que resulta de la resta en entero de
10 - 0, strtoint(maskedit2.text) - strtoint(maskedit1.text). La longitud del vector se determina con el valor del combobox, los valores posibles pueden ser 0.1, 0.2, 0.5 o 1. Esto quiere decir que si en el combobox se selecciona 0.2 cada posición del vector aumentará 0.2. Para el ejemplo de 0 a 10, el vector tendrá una longitud de 50, resultante de 0.2/10, algo así es lo deseado: [0 0.2 0.4 0.6 .... 9.6 9.8 10]

El problema es que justo en las posiciones 23 a 27 del vector resultan valores con exponenciales muy pequeños cercanos a cero, al usar la función trunc() se vuelven cero. Entre la posición cero y la veintidos todo bien, y partir de la 28 todo bien.

Para comprobar, escribo cada posición del vector en una línea de un memo. El evento se genera al presionar un botón. Aquí el código:

Código Delphi [-]
var
  
  LI, LS, ND : Integer;                   //LI: límite inferior, LS: límite superior, ND: número de divisiones
  x1 : Real;                                 //Acumulador
  RES1 : Real;                              //Resolución de las variables

procedure TForm1.Button1Click(Sender: TObject);
var
i : Integer;
begin
  if ComboBox1.Text = '1' then
  begin
    LI1 := StrToInt(MaskEdit1.Text);          //Límite inferior en entero
    LS1 := StrToInt(MaskEdit2.Text);         //Límite superior en entero
    RES1 := StrToFloat(ComboBox1.Text);  //Resolución en real
    RE1 := LS1 - LI1;                              //Rango de la variable
    ND1 := trunc(RE1 / RES1);                 //Número de divisiones
    SetLength(VE1, RE1);                         //Se establece longitud del vector

    for i := 0 to ND1 do
      begin
        VE1[i] := LI1 + x1;
        x1 := x1 + RES1;
      end;

    for i := 0 to ND1 do
     begin
      Memo1.Lines.Add(FloatToStr(StrToFloat(FormatFloat('0.00', VE1[i]))));    //Con formato float se redondea y se da cero en la posición 23-27
      //Memo1.Lines.Add(FloatToStr(VE1[i]));                                              //En este formato las posiciones 23 a 27 tienen valores                         
                                                                                                          //exponenciales cercanos a cero
     end;

De antemano muchas gracias por su ayuda y su tiempo.

MoeHoward 16-10-2015 04:04:05

olvidé mencionar:

VE1 : array of Real;
RE1 : Integer;

ecfisa 16-10-2015 07:05:47

Hola MoeHoward, bienvenido a los foros de Club Delphi :)

Y como acostumbramos con los ingresantes, te invitamos a que leas nuestra guía de estilo.

Si no interpreté mal la consigna, tu código está bién encaminado. Pero veo algunos detalles:
  • Solo ejecuta para el valor 1 del ComboBox.
  • La línea:
    Código Delphi [-]
    for i := 0 to ND1 do
  • tendría que ser:
    Código Delphi [-]
    for i := 0 to ND1-1 do
  • Y en lugar de la función Trunc, tendrias que usar la función Round
Quedaría así:
Código Delphi [-]
procedure TForm1.Button2Click(Sender: TObject);
var
  i : Integer;
  LI1, LS1, ND1 : Integer;  //LI: límite inferior, LS: límite superior, ND: número de divisiones
  x1 : Real;                //Acumulador
  RES1 : Real;              //Resolución de las variables
  VE1 : array of Real;
  RE1 : Integer;
begin
  LI1 := StrToInt(MaskEdit1.Text);     //Límite inferior en entero
  LS1 := StrToInt(MaskEdit2.Text);     //Límite superior en entero
  RES1 := StrToFloat(ComboBox1.Text);  //Resolución en real
  RE1 := LS1 - LI1;                    //Rango de la variable
  ND1 := Round(RE1/RES1);              //Número de divisiones
  SetLength(VE1, ND1);                 //Se establece longitud del vector

  x1 := 0;
  // Dec(ND1);  para evitar: ND1-1
  for i := 0 to ND1-1 do
  begin
    VE1[i] := x1;
    x1 := x1 + RES1;
  end;
  // mostrar valores en el memo
  Memo1.Clear;
  for i := 0 to ND1-1 do
    Memo1.Lines.Add(Format('v[%.2d] = %3.2f',[i, VE1[i]]))
end;

Se puede optimizar un poco,
Código Delphi [-]
procedure TForm1.Button1Click(Sender: TObject);
var
  v                : array of Double;
  i,topInf, topSup : Integer;
  Delta, Incr      : Double;;
begin
  topInf := StrToIntDef(MaskEdit1.Text, 0);
  topSup := StrToIntDef(MaskEdit2.Text, 0);
  if (TopSup-TopInf > 0) and (ComboBox1.ItemIndex <> -1) then
  begin
    delta := StrToFloat(ComboBox1.Items[ComboBox1.ItemIndex]);
    SetLength(v, Round((TopSup-TopInf) / Delta));

    Incr := 0;
    for i := Low(v) to High(v) do
    begin
      v[i] := Incr;
      Incr := Incr + Delta;
    end;

    // mostrar valores en el memo
    Memo1.Clear;
    for i := Low(v) to High(v) do
      Memo1.Lines.Add(Format('v[%.2d] = %3.2f',[i,v[i]]))
  end
  else
    ShowMessage('Revise los datos de ingreso');
end;
El control de ingreso no es muy exaustivo para no complicar el código (tal vez te convendría usar SpinEdits en lugar de los MaskEdits).

Saludos :)

MoeHoward 24-10-2015 05:01:38

Muchas gracias ecfisa!
Ya resolví el problema, me sirvió mucho tu explicación así con detalles y con la optimización del código.
El problema estaba en que me equivoqué al definir la longitud de mi vector con otra variable(RES1 en lugar de RE1), algo muy simple jeje.

Gracias por todo, saludos.

AgustinOrtu 24-10-2015 05:11:29

Por cierto, yo lo primero que vi con olor es el uso del tipo Real

Yo ni sabia de la existencia de ese tipo, bueno si que estaba en Pascal, pero no sabia que venia con Delphi. Yo siempre uso Single o Double

Es mas, acá se aconseja lo mismo debido a que el tipo Real esta obsoleto

El Double es el mas "comun" por decirlo de una manera. Tiene balance de precision/velocidad
El Single es mas rápido que el Double, pero pierde precision
El Extended es el más lento pero el de mayor precision

Saludos

MoeHoward 03-11-2015 00:31:48

Gracias, lo tomaré en cuenta ya que en el programa ocupo de un gran número de variables que son de este tipo.


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

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