- Questo topic ha 10 risposte, 4 partecipanti ed è stato aggiornato l'ultima volta 13 anni, 10 mesi fa da
Marco87.
-
CreatoreTopic
-
29 Ottobre 2012 alle 14:25 #80143::
Ciao a tutti,sto cercando di inserire un condizionale in un nuovo comando che sto cercando di scrivere. All’interno del comando vengono calcolate due distanze, con il comando [tt]\calcLV[/tt] indicato in questa discussione. Dopo ciò viene calcolata la loro differenza:
`\pgfmathsetmacro{\differenza}{\distA-\distB}`
A questo punto vorrei inserire un condizionale, il quale, se [tt]\differenza[/tt] è nullo deve eseguire un certo codice, altrimenti un altro (ovviamente). Ho provato così:
`\if \differenza = 0
…
\else
…
\fi`
ma non funziona. Non mi vengono indicati errori in fase di compilazione, ma semplicemente non ottengo il comportamento corretto di [tt]\if.[/tt] Cosa sbaglio?Grazie e buona giornata,
Marco.
-
CreatoreTopic
-
AutoreRisposte
-
-
29 Ottobre 2012 alle 15:19 #80144::
Marco87″ post=79330Ciao a tutti,
sto cercando di inserire un condizionale in un nuovo comando che sto cercando di scrivere. All’interno del comando vengono calcolate due distanze, con il comando [tt]\calcLV[/tt] indicato in questa discussione. Dopo ciò viene calcolata la loro differenza:
`\pgfmathsetmacro{\differenza}{\distA-\distB}`
A questo punto vorrei inserire un condizionale, il quale, se [tt]\differenza[/tt] è nullo deve eseguire un certo codice, altrimenti un altro (ovviamente). Ho provato così:
`\if \differenza = 0
…
\else
…
\fi`
ma non funziona. Non mi vengono indicati errori in fase di compilazione, ma semplicemente non ottengo il comportamento corretto di [tt]\if.[/tt] Cosa sbaglio?Grazie e buona giornata,
Marco.Immagino che [tt]\differenza[/tt] contenga una dimensione in punti; in tal caso il condizionale da usare è [tt]\ifdim[/tt]:
`\ifdim\differenza = 0pt
…
\else
…
\fi`Il condizionale [tt]\if[/tt] serve per confrontare due token in base al loro “character code”.
Ciao
Enrico
-
29 Ottobre 2012 alle 18:42 #80145::
Ciao Enrico,egreg9Immagino che [tt]\differenza[/tt] contenga una dimensione in punti;
A dire il vero non ne sono sicuro. Il comando [tt]\calcLV[/tt] mostrato nella discussione di cui ho fornito il link nel mio messaggio precedente, determina la distanza fra due punti. Il risultato è fornito in pt, ma non so se si porti dietro anche l’unità di misura; in merito sono parecchio ignorante. 🙁
Se scrivo:
`\ifdim\differenza = 0pt
…
\else
…
\fi`
mi viene dato il seguente errore:Illegal unit of measure (pt inserted).
= Se invece scrivo:
`\ifdim\differenza pt = 0pt
…
\else
…
\fi`
l’errore scompare, ma il comportamento del codice mostra che quell’uguaglianza non viene verificata correttamente.Grazie e buona serata,
Marco.
-
29 Ottobre 2012 alle 22:48 #80146::
Marco87″ post=79337Ciao Enrico,
Immagino che [tt]\differenza[/tt] contenga una dimensione in punti;
A dire il vero non ne sono sicuro. Il comando [tt]\calcLV[/tt] mostrato nella discussione di cui ho fornito il link nel mio messaggio precedente, determina la distanza fra due punti. Il risultato è fornito in pt, ma non so se si porti dietro anche l’unità di misura; in merito sono parecchio ignorante. 🙁
Se scrivo:
`\ifdim\differenza = 0pt
…
\else
…
\fi`
mi viene dato il seguente errore:Illegal unit of measure (pt inserted).
= Se invece scrivo:
`\ifdim\differenza pt = 0pt
…
\else
…
\fi`
l’errore scompare, ma il comportamento del codice mostra che quell’uguaglianza non viene verificata correttamente.Grazie e buona serata,
Marco.Esempio completo, per favore.
Ciao
Enrico
-
30 Ottobre 2012 alle 12:10 #80147::
Ciao Enrico,chiedo scusa. Ecco un codice che riproduce il comportamento che ho descritto:
`\documentclass[a4paper,11pt,extrafontsizes,twoside,openright]{memoir}
\usepackage{etex}
\usepackage[T1]{fontenc}
\usepackage[utf8]{inputenc}
\usepackage[greek,italian]{babel}
\usepackage{microtype}
\pagestyle{empty}
\usepackage{ifthen}\usepackage{xcolor}
\usepackage{tikz}
% Librerie
\usetikzlibrary{automata}
\usetikzlibrary{arrows}
\usetikzlibrary{backgrounds}
\usetikzlibrary{calc}
\usetikzlibrary{hobby}
\usetikzlibrary{intersections}
\usetikzlibrary{patterns}
\usetikzlibrary{positioning}
\usetikzlibrary{shadows}
\usetikzlibrary{shapes}
\usetikzlibrary{through}
% Pacchetti
\usepackage{tkz-euclide}
\usetkzobj{all}% TikZ
%Distanza fra due punti (la lunghezza viene espressa in punti, quindi usare \calcLV pt)
\makeatletter
\def\calcLV(#1,#2)#3{%
\pgfpointdiff{\pgfpointanchor{#1}{center}}%
{\pgfpointanchor{#2}{center}}%
\pgf@xa=\pgf@x%
\pgf@ya=\pgf@y%
\FPeval\@temp@a{\pgfmath@tonumber{\pgf@xa}}%
\FPeval\@temp@b{\pgfmath@tonumber{\pgf@ya}}%
\FPeval\@temp@sum{(\@temp@a*\@temp@a+\@temp@b*\@temp@b)}%
\FProot{\FPMathLen}{\@temp@sum}{2}%
\FPround\FPMathLen\FPMathLen5\relax
\global\expandafter\edef\csname #3\endcsname{\FPMathLen}
}
\makeatother% Distanza fra due punti lungo X (la lunghezza viene espressa in punti, quindi usare \calcLVX pt)
\makeatletter
\def\calcLVX(#1,#2)#3{%
\pgfpointdiff{\pgfpointanchor{#1}{center}}%
{\pgfpointanchor{#2}{center}}%
\pgf@xa=\pgf@x%
\FPeval\@temp@a{\pgfmath@tonumber{\pgf@xa}}%
\FPround\@temp@a\@temp@a5\relax
\global\expandafter\edef\csname #3\endcsname{\@temp@a}
}
\makeatother% Distanza fra due punti lungo Y (la lunghezza viene espressa in punti, quindi usare \calcLVY pt)
\makeatletter
\def\calcLVY(#1,#2)#3{%
\pgfpointdiff{\pgfpointanchor{#1}{center}}%
{\pgfpointanchor{#2}{center}}%
\pgf@ya=\pgf@y%
\FPeval\@temp@a{\pgfmath@tonumber{\pgf@ya}}%
\FPround\@temp@a\@temp@a5\relax
\global\expandafter\edef\csname #3\endcsname{\@temp@a}
}
\makeatother% MIO NUOVO COMMANDO
\newcommand{\my}[4]{%
\coordinate (medio) at ($(#1)!.5!(#2)$);
\calcLV(#1,medio){dist}
\coordinate (o) at (0,0);
\coordinate (temp) at (#3,0);
\calcLV(o,temp){rag}
\pgfmathsetmacro{\differenza}{\dist-\rag}
%
\ifdim \differenza pt = 0 pt
\def\abc{2}
\else
\def\abc{3}
\fi
}\begin{document}
\begin{tikzpicture}[scale=1]
\draw [help lines] (0,0) grid (3,3);
\coordinate [label={270:\tiny $O$}] (or) at (0,0);
\coordinate [label={270:\tiny $A$}] (a) at (50:2);
\coordinate [label={270:\tiny $B$}] (b) at (50+180:2);\my{a}{b}{2}{}
\fill [black] (a) circle (1.5pt);
\fill [black] (b) circle (1.5pt);
\fill [cyan] (\abc,\abc) circle (2pt);\end{tikzpicture}
\end{document}`
Nel comando [tt]\my[/tt] quello che faccio (cerco di fare) per ora è eseguire questo:- Dati due punti, ne creo uno posto esattamente al centro;
- Misuro la distanza che c’è tra questo e uno dei due punti forniti in ingresso;
- Converto il raggio inserito in ingresso in pt (sull’efficienza del mio codice credo che ci sia molto da dire);
- Calcolo la differenza che c’è tra queste due distanze;
- A seconda del valore di questa differenza eseguo un codice o un altro.
Nell’esempio che ho riportato [tt]\differenza[/tt] dovrebbe essere nulla, di conseguenza [tt]\abc[/tt] dovrebbe essere pari a [tt]2,[/tt] e quindi il punto azzurro dovrebbe avere coordinate [tt](2,2),[/tt] ma non è così. Cosa sbaglio?
Grazie e buona giornata,
Marco.
-
30 Ottobre 2012 alle 12:41 #80148::
Marco87″ post=79354Ciao Enrico,
chiedo scusa. Ecco un codice che riproduce il comportamento che ho descritto:
`\documentclass[a4paper,11pt,extrafontsizes,twoside,openright]{memoir}
\usepackage{etex}
\usepackage[T1]{fontenc}
\usepackage[utf8]{inputenc}
\usepackage[greek,italian]{babel}
\usepackage{microtype}
\pagestyle{empty}
\usepackage{ifthen}\usepackage{xcolor}
\usepackage{tikz}
% Librerie
\usetikzlibrary{automata}
\usetikzlibrary{arrows}
\usetikzlibrary{backgrounds}
\usetikzlibrary{calc}
\usetikzlibrary{hobby}
\usetikzlibrary{intersections}
\usetikzlibrary{patterns}
\usetikzlibrary{positioning}
\usetikzlibrary{shadows}
\usetikzlibrary{shapes}
\usetikzlibrary{through}
% Pacchetti
\usepackage{tkz-euclide}
\usetkzobj{all}% TikZ
%Distanza fra due punti (la lunghezza viene espressa in punti, quindi usare \calcLV pt)
\makeatletter
\def\calcLV(#1,#2)#3{%
\pgfpointdiff{\pgfpointanchor{#1}{center}}%
{\pgfpointanchor{#2}{center}}%
\pgf@xa=\pgf@x%
\pgf@ya=\pgf@y%
\FPeval\@temp@a{\pgfmath@tonumber{\pgf@xa}}%
\FPeval\@temp@b{\pgfmath@tonumber{\pgf@ya}}%
\FPeval\@temp@sum{(\@temp@a*\@temp@a+\@temp@b*\@temp@b)}%
\FProot{\FPMathLen}{\@temp@sum}{2}%
\FPround\FPMathLen\FPMathLen5\relax
\global\expandafter\edef\csname #3\endcsname{\FPMathLen}
}
\makeatother% Distanza fra due punti lungo X (la lunghezza viene espressa in punti, quindi usare \calcLVX pt)
\makeatletter
\def\calcLVX(#1,#2)#3{%
\pgfpointdiff{\pgfpointanchor{#1}{center}}%
{\pgfpointanchor{#2}{center}}%
\pgf@xa=\pgf@x%
\FPeval\@temp@a{\pgfmath@tonumber{\pgf@xa}}%
\FPround\@temp@a\@temp@a5\relax
\global\expandafter\edef\csname #3\endcsname{\@temp@a}
}
\makeatother% Distanza fra due punti lungo Y (la lunghezza viene espressa in punti, quindi usare \calcLVY pt)
\makeatletter
\def\calcLVY(#1,#2)#3{%
\pgfpointdiff{\pgfpointanchor{#1}{center}}%
{\pgfpointanchor{#2}{center}}%
\pgf@ya=\pgf@y%
\FPeval\@temp@a{\pgfmath@tonumber{\pgf@ya}}%
\FPround\@temp@a\@temp@a5\relax
\global\expandafter\edef\csname #3\endcsname{\@temp@a}
}
\makeatother% MIO NUOVO COMMANDO
\newcommand{\my}[4]{%
\coordinate (medio) at ($(#1)!.5!(#2)$);
\calcLV(#1,medio){dist}
\coordinate (o) at (0,0);
\coordinate (temp) at (#3,0);
\calcLV(o,temp){rag}
\pgfmathsetmacro{\differenza}{\dist-\rag}
%
\ifdim \differenza pt = 0 pt
\def\abc{2}
\else
\def\abc{3}
\fi
}\begin{document}
\begin{tikzpicture}[scale=1]
\draw [help lines] (0,0) grid (3,3);
\coordinate [label={270:\tiny $O$}] (or) at (0,0);
\coordinate [label={270:\tiny $A$}] (a) at (50:2);
\coordinate [label={270:\tiny $B$}] (b) at (50+180:2);\my{a}{b}{2}{}
\fill [black] (a) circle (1.5pt);
\fill [black] (b) circle (1.5pt);
\fill [cyan] (\abc,\abc) circle (2pt);\end{tikzpicture}
\end{document}`
Nel comando [tt]\my[/tt] quello che faccio (cerco di fare) per ora è eseguire questo:- Dati due punti, ne creo uno posto esattamente al centro;
- Misuro la distanza che c’è tra questo e uno dei due punti forniti in ingresso;
- Converto il raggio inserito in ingresso in pt (sull’efficienza del mio codice credo che ci sia molto da dire);
- Calcolo la differenza che c’è tra queste due distanze;
- A seconda del valore di questa differenza eseguo un codice o un altro.
Nell’esempio che ho riportato [tt]\differenza[/tt] dovrebbe essere nulla, di conseguenza [tt]\abc[/tt] dovrebbe essere pari a [tt]2,[/tt] e quindi il punto azzurro dovrebbe avere coordinate [tt](2,2),[/tt] ma non è così. Cosa sbaglio?
Grazie e buona giornata,
Marco.Alcuni consigli:
1) puoi fare un po’ di debug creando un nodo e stampando le misure che ti servono. Esempio:
`\newcommand{\my}[4]{%
\coordinate (medio) at ($(#1)!.5!(#2)$);
\calcLV(#1,medio){dist}
\coordinate (o) at (0,0);
\coordinate (temp) at (#3,0);
\calcLV(o,temp){rag}\node at (o) {\rag};
\pgfmathsetmacro{\differenza}{\dist-\rag}
\node at ($(medio)!0..5!(o)$) {\differenza};
%
\ifdim \differenza pt = 0 pt
\def\abc{2}
\else
\def\abc{3}
\fi
}`
È una cosa abbastanza utile che permette di capire se ci sono errori grossi.2) Puoi utilizzare funzioni interne di pgf; cerca sul manuale Comparison and logical functions. O anche il pacchetto etoolbox.
3) A volte è necessario andare a spulciare proprio il codice di pgf per capire alcune cose (parlo in primis per le librerie).. in genere poi uno si deprime perché non è proprio banale, però aiuta. Ad esempio tu stai utilizzando il pacchetto pgfmath. Vai sul terminale e digita (beh.. se utilizzi linux)
`
gedit $(kpsewhich pgfmath.sty)
`
Ti aprirà il file con il codice del pacchetto. Ora preparati a qualche decina di scatole cinesi.. ogni volta che trovi qualche [tt]\input[/tt] in teoria è qualcosa di interessante. Ad esempio, pgfmath.sty è così composto:`
\input{pgfmath.code.tex}\endinput
` Apri quindi [tt]pgfmath.code.tex[/tt] con:
`
gedit $(kpsewhich pgfmath.code.tex)
` Perciò sono di potenziale interesse [tt]pgfmathcalc.code.tex[/tt] e [tt]pgfmathfloat.code.tex[/tt]. Continua ad aprire i vari files come prima; ad esempio, a te serve [tt]pgfmathcalc.code.tex[/tt]:
`
gedit $(kpsewhich pgfmathcalc.code.tex)
` E così via.Ciao
Claudio
-
30 Ottobre 2012 alle 13:31 #80149::
Ciao Claudio,ti ringrazio molto. In effetti non pensavo che si potesse far stampare in quel modo il valore contenuto in [tt]\differenza.[/tt] L’errore era dovuto alla precisione con cui il comando [tt]\calcLV[/tt] eseguiva i calcoli (arrotondando a 5 cifre decimali, se non sbaglio). Visto che nel mio caso la precisione di macchina è dell’ordine di 10-16, ho sostituito questa riga di definizione del comando [tt]\calcLV:[/tt]
`\FPround\FPMathLen\FPMathLen5\relax`
con questa:
`\FPround\FPMathLen\FPMathLen17\relax`
In questo modo dovrei avere la massima precisione possibile. Così facendo il valore di [tt]\differenza[/tt] visualizzato è di 0.0, e il codice del mio nuovo comando funziona correttamente.cfiandrabeh.. se utilizzi linux
In realtà no; almeno per ora, sono un “leale” sostenitore e utilizzatore di Windows. Comunque cercherò in altri modi quei file e cercherò di seguire i tuoi consigli.
Grazie mille e buona serata,
Marco.
-
30 Ottobre 2012 alle 13:47 #80150
-
30 Ottobre 2012 alle 16:31 #80151::
Con la macro che davi come esempio, trovo che con la definizione di (b) originale, \differenza si espande a -0.00018 e la macro segue il ramo falso. Altrettanto con la seconda definizione di (b), la differenza stavolta è -0.00233.Se chiedo quanto siano \dist e \rag, la risposta è 56.9. Con l’arrotondamento a cinque sole cifre, trovo 56.90530 per \dist e 56.90549 per \rag. Temo che tu stia eseguendo calcoli in modo scorretto dal punto di vista dell’analisi numerica.
Ciao
Enrico
-
30 Ottobre 2012 alle 16:46 #80152::
Marco, il fatto che il tuo processore consenta la doppia precisione e ti garantisca 10 cifre significative “esatte” non credo che abbia nulla a che vedere con la precisione con cui pgfmath faccia i conti.il pacchetto fp (floating point) apparentemente garantisce un precisione quasi illimitata, ma è lento perché fa i calcoli simulando i contatori floating point di un processore a 64bit con un numero adeguato di contatori interi TeX, e simula i calcoli (che nella CPU vengono fatti con pochi cicli di clock) lavorando con una cifra alla volta come si farebbe a mano su un quaderno quadrettato.
TeX fa conto solo con quantità intere.
Calc e le nuove istruzioni di e-TeX (già incorporate in pdftex e xetex, i motori di composizioni “normali, e luatex che però può ricorrere ai calcoli in ambiente Lua) sembra che eseguano i conti con quantità fratte, ma in realtà lavorano con grandezze in punti espresse come valori interi di scaled points, ovvero, il che è in pratica lo stesso, con valori fratti in punti, a a virgola fissa e con 16 cifre binarie nella parte fratta. per la parte intera si arriva solo a 14 cifre binarie, quindi la massima grandezza in valore assoluto è di 16 384pt, anzi, per l’esattezza 16383.99999pt.
Ne segue che il massimo numero di cifre fratte che si possono usare in aritmetica a virgola fisse, come quella che usano tex, pdftex, xetex, equivale ad una “precisione” di circa 5 o 6 cifre decimali fratte. Non puoi fare di meglio se non usare il pacchetto fp, che però è lentissimo.
Tutto ciò premesso, i calcoli a virgola fisse implicano degli errori di troncamento o di arrotondamento ad ogni operazione eseguita, per cui le cifre “esatte” alla fine di qualunque conto sono meno di 5 cifre fratte.
In qualunque corso di programmazione si insegna che i confronti con lo zero sono banali lavorando con gli interi, e sono difficili con i numeri fratti a causa di questi arrotondamenti e troncamenti. Il concetto sostanzialmente è che invece di confrontare qualcosa con lo zero bisogna confrontare il valore assoluto di quel qualcosa con un numero piccolo e non nullo. In termini logico-matematici in aritmetica finita a virgola mobile, bisognerebbe confrontare due quantità relativa, per esempio, detta D la distanza calcolata e D0 una distanza di riferimento bisognerebbe confrontare ` |D/D0| < epsilon` dove epsilon è una quantità positiva sufficientemente piccola, abbastanza minore di uno ma non così piccola da non poter essere rappresentata nell'aritmetica finita di TeX; potrebbe andare bene qualcosa come 0.001pt. Allora il test eseguito è vero se se il primo valore assoluto è minore di epsilon, vale a dire che in quel caso D si può considerare trascurabile rispetto a D0, quindi, scelto D0 in modo adeguato, ma in modo che sia paragonabile col il massimo delle addendi algebrici usati nei calcoli precedenti, allora D si può considerare nullo entro la tolleranza relativa stabilita con epsilon. Il fatto che possa impostare il limite del troncamento ad un valore qualsiasi con i comandi che presenti, non mi sembra una cosa da fare e lo considererei un bug di pgfmath se consente di farlo. Non sperare di poter mai ottenere differenze nulle fra distanze lavorando con i programmi del sistema TeX; Non ci riusciresti nemmeno se usassi triangoli pitagorei; nel momento in cui calcoli, per esempio, la radice quadrata di x al quadrato più y al quadrato dove x=3 e y=4, non sperare di ottenere 5; al meglio potrai ottenere 4.99973 oppure 5,00013 o cose del genere. Non voglio deprimerti con queste indicazioni, ma sperare di poter ottenere dei valori nulli eseguendo delle differenze fra numeri fratti è praticamente impossibile.
-
31 Ottobre 2012 alle 7:27 #80153
-
-
AutoreRisposte
- Devi essere connesso per rispondere a questo topic.