Problema con il tipo float

Ho iniziato da poco a programmare in ruby, e stavo facendo un piccolo
programma che, dato un sistema di disequazioni, trova i punti comuni a
queste, impostando un problema di programmazione lineare.
Viene chiesto in input prima il numero di disequazioni (vincoli) e
quindi i parametri in questo modo:
ax+by+c>=0
prima il coefficiente di x, quindi quello di y, il termine noto, e
infine un quarto parametro da impostare ad 1 o a -1 per il segno della
disequazione.
Ho provato il seguente sistema:
0.9x+1.5y<=45
x+y<=36
x>=10
y>=0
Quindi inserisco da input:
4 | 0.9 | 1.5 | 45 | -1 | 1 | 1 | 36 | -1 | 1 | 0 | 10 | 1 | 0 | 1 | 0 |
1
I punti in comune calcolati a mano sono:
(10,0) (36,0) (15,21) (10,24)
E qui sorge il problema: il programma mi scarta il punto (15,21) alla
prima disequazione (provate a mano, la verifica!) e la fatidica somma
0.90.15+1.521-45 ridà nientepocodimenoche 7.105427357601e-015!!!
Fatta numericamente dà 0, eppure il programma sputa fuori questo
risultato!
Sono ore che ci combatto, datemi una mano vi prego!
Grazie in anticipo!

Il file principale è allegato, seguono le due piccole classi che ho
implementato:

point.rb

class Point
attr_reader :x, :y
def initialize (x,y)
@x=x
@y=y
end
end

diseq.rb

require ‘myrbs\point’

class Diseq < Point
attr_reader :t,:s
def initialize (x,y,t,s)
super(x,y)
@t=t
@s=s
end
def solve(a,b)
c=xa+yb-t
puts c
if(c*s>=0)
o=1
else
o=0
end
o
end
end

Matteo M. ha scritto:

0.90.15+1.521-45 ridà nientepocodimenoche 7.105427357601e-015!!!
Fatta numericamente dà 0

A me questa somma non dà zero, sono corretti i numeri che hai scritto?
:slight_smile:

Dopo essermi concentrato sui dati ed aver capito che avevi solo messo un
punto in più (sarà l’ora meglio andare a dormire sono stonato), ho
digitato in irb il tuo programma e sembra funzionare correttamente.

Domani lo provo sul mac e ti faccio sapere (win ok).

Matteo M. ha scritto:

Confermo che anche dal Mac gira tutto correttamente.

Il giorno 08/ott/07, alle ore 23:09, Matteo M. ha scritto:

Ho iniziato da poco a programmare in ruby, e stavo facendo un piccolo
programma che, dato un sistema di disequazioni, trova i punti comuni a
queste, impostando un problema di programmazione lineare.
Viene chiesto in input prima il numero di disequazioni (vincoli) e
quindi i parametri in questo modo:

[…]

Premetto che nel primo post, causa sonno, ho scritto 0.90.15+1.521-45
che effettivamente non è nulla come espressione, anzichè
0.915+1.521-45.
La versione che sto usando è la 1.8.6 su (ahimè) windows xp.
Grazie mille per le risposte, ho capito qual’è il problema e appena ho
un attimo di tempo aggiusto il codice.

Matteo M. [email protected] writes:

Ho iniziato da poco a programmare in ruby, e stavo facendo un piccolo
programma che, dato un sistema di disequazioni, trova i punti comuni a
queste, impostando un problema di programmazione lineare.

A tal proposito un piccolo suggerimento. Invece di fare

i = 0
numero.times do

i = i + 1
end

puoi direttamente:

numero.times { |i|

end

E qui sorge il problema: il programma mi scarta il punto (15,21) alla
prima disequazione (provate a mano, la verifica!) e la fatidica somma
0.90.15+1.521-45 ridà nientepocodimenoche 7.105427357601e-015!!!

Che di fatto é zero per la precisione che stai utilizzando nel tuo
input. Sul mio pc da 0.0 ma devi distinguere tra rappresentazione in
stringa del numero float e quello che effettivamente é memorizzato
come Float.

Dicci che versione di ruby stai usando, probabilmente le piu’ recenti
troncano il risultato alle prime cifre, mentre la tua cerca di farti
vedere il numero effettivamente memorizzato usando la notazione
scientifica.

Comunque se sostituisco i tuoi

puts numero

con

puts “%.60f” % numero

e vedo le prime 60 cifre decimali allora vedo anche io un risultato
parziale del tipo:
0.000000000000007105427357601001858711242675781250000000000000

Questo é problema (non di ruby) tipico di chi lavora con i float,
dovuto a come i computer rappresentano tali numeri.
Ti suggerisco questa lettura:

http://docs.sun.com/source/806-3568/ncg_goldberg.html

Fatta numericamente dà 0, eppure il programma sputa fuori questo
risultato!

Quando visualizzi i risultati troncalo alle prime cifre decimali che
ti interessano (es. puts “%.4f” % risultato) e vedrai che avrai il tuo
0.

In generale verificare uguaglianze tra approssimazioni e’ quasi una
follia, devi controllare se due numeri sono molto vicini una volta
stabilita’ una tolleranza. Es.

def eq( x, y, epsilon = Float::EPSILON * 4)
x == y or (x-y).abs < (x.abs + y.abs + 1.0) * epsilon
end

Prova ad usarla su irb e capirai ancora meglio:

0.01 + 0.05 == 0.06

da false

mentre

eq(0.01+0.05, 0.06)

da true

Questa puo’ andar bene per molte applicazioni (dipende dal tipo di
calcoli…).

Domanda da principiante: c’è un modo per impostare ‘globalmente’ la
precisione dei float?

Ho provato a fare una semplice classe double con il codice che hai
postato ma comunque incontra problemi nel fatidico numero:

0
10
0
7.105427358e-015
./myrbs\diseq.rb:13:in *': String can't be coerced into Float (TypeError) from ./myrbs\diseq.rb:13:insolve’
from myrbs/area.rb:45

Se non posti il codice (quello con le modifiche non diseq.rb che é
rimasto invariato), é difficile capire perché non funziona…

Matteo M. [email protected] writes:

Domanda da principiante: c’è un modo per impostare ‘globalmente’ la
precisione dei float?

Il tuo problema non é relativo alla precisione dei float ma come
rappresenti i float con stringhe. La precisione dei float di Ruby é
gia’ abbastanza elevata per il maggior numero di applicazioni.

Se vuoi stampare un float con al piu’ un tot numero di cifre usa la
stampa printf-like, e.g.:

puts “%.10g” % numero

se vuoi che venga fatto “globalmente” in automatico puoi sempre
ridefinire il metodo to_s che viene chiamato per convertire in stringa
un oggetto con

class Float < Numeric
def to_s
“%.10g” % self
end
end

Pardon. Allego qui.

This forum is not affiliated to the Ruby language, Ruby on Rails framework, nor any Ruby applications discussed here.

| Privacy Policy | Terms of Service | Remote Ruby Jobs