Divisione con sole sottrazioni

tony19
il mio computer ha avuto un ictus, e l'unica operazione che riesce a fare l'unità aritmetica è la sottrazione.
vorrei gradualmente riabilitarlo con del software.

son fermo su un punto che forse è banale, ma la testa mi fuma (approfittando degli ultimi giorni prima dell'entrata in vigore dell'ennesimo divieto):

come si può eseguire una divisione con sole sottrazioni, ottenendo un quoziente con un numero prefissato di decimali?
es. 31416:1000=31,416
a mano, intendo; poi ci penso io a programmare l'algoritmo

grazie per l'aiuto
(in realtà il mio computer gode di discreta salute e l'arzigogolo mi servirebbe per render più pulita una mia soluzione ad un grazioso quesito di karl: radice quadrata con sole sottrazioni)

tony

Risposte
vecchio1
beh...io provo così...
basta contare il numero di volte che sottraggo per il divisore...
es.

216:100= ?

n° sottrazioni per 100
1)216-100=116
2)116-100=16
non sono possibili ulteriori sottrazioni dunque la parte intera del quoziente sarà 2.

216:100=2,...

per trovare la parte decimale basta prendere il 16 dalla 2) e sottrarlo per 10 (cioè 100 con la virgola spostata di un decimale [per gli amici la divisione per 10...ma visto che il PC non conosce la divisione..])

n° sottrazioni per 10
1) 16-10=6

la prima cifra decimale sarà 1

216:100=2,1...

ora prendo il 6 e lo sottraggo per 1 (il 10 spostando la virgola)
1)6-1=5
2)5-1=4
...
6)1-1=0

la seconda cifra decimale è dunque 6

216:100=2,16

saluti il vecchio


tony19
grazie, vecchio
quote:
beh...io provo così...
basta contare il numero di volte che sottraggo per il divisore...
es.[vecchio]

ma quando arrivi a dire
"
con la virgola spostata di un decimale [per gli amici la divisione per 10...ma visto che il PC non conosce la divisione..])
216:100= ?
"
stai comunque spostando la virgola, e questa, a seconda della direzione, è classificabile solo come una motiplicazione o come una -dannata- divisione
o no?
io l'avevo buttata lì, ma ora sono perplesso: si può fare?

tony

drake53
Per trovare successivamente le cifre decimali avrei moltiplicato per 10 ogni resto successivo.
Per moltiplicare per 10 sottraggo 9 volte il negativo del resto stesso ottenuto per
differenza dallo zero.
Nell'esempio di Vecchio:

16 - (0-16) - (0-16) .... = 160

per la prima cifra decimale si contano ora le volte da risottrarre 100 e si itera.

Drake

vecchio1
si giusto... è la stessa cosa...o "dividi" per 10 il divisore, o "moltiplichi" per 10 il resto...e forse visto che la moltiplicazione è più facile da esprimere conviene fare come ha fatto Drake...all'inizio non capivo perchè non sommava semplicemente 10 volte il numero stesso...poi mi sono ricordato dell'inghippo..il PC fa solo sottrazioni!! quindi ok così...direi che il problema è risolto!
saluti
il vecchio


tony19
grazie, ragazzi, ma, scusatemi: sono stanco e appannato; ho bisogno di una vacanza.

la moltiplicazione l'avevo già realizzata nell'esercizietto citato (sennò addio "radice quadrata alla karl" coi decimali); quindi do come scontato che la macchina oltre che sottrarre, ora sappia anche (via software) addizionare e moltiplicare.

ma non riesco a mettere in pratica il vostro suggerimento; potreste farmi un esempietto di divisione con tutti i passaggi di calcolo, e non con la generica dicitura "trovare le successive cifre decimali" ?

quando ne ho trovata una, dove la sommo?
(non voglio usare un array di costanti 1/10, 1/100, 1/1000, ricadrei nalla stortura di quell'esercizietto che partiva da un antipatico 2^-26)
usate pure il verbo "moltiplicare" o il simbolo corrispondente.

grazie ancora

tony il duro (di comprendonio)

vecchio1
se non mi parte di nuovo la corrente mentre scrivo te lo spiego...


vecchio1
allora...
facciamo ad esempio 113:15 che la calcolatrice mi dice fare 7.53333...
allora...
per calcolare la parte intera basta "contare" (quindo che sia opportuno utilizzare un contatore nel tuo programma) quante volte è possibile sottrarre 15 da 113...
1)113-15=98
2)98-15=83
3)83-15=68
4)68-15=53
5)53-15=38
6)38-15=23
7)23-15=8
non è più possibile sottrarre...quindi la parte intera è 7 e il resto è 8


vecchio1
a questo punto calcolo la PRIMA cifra decimale...
prendo il resto di prima, lo moltiplico per dieci e "conto" quante volte posso sottrarre il 15...
1)80-15=65
2)65-15=50
3)50-15=35
4)35-15=20
5)20-15=5
non posso andare avanti...la prima cifra decimale è 5 il resto è 5


vecchio1
per la SECONDA cifra decimale...
prendo il resto di prima e lo moltiplico per 10...etc...
1)50-15=35
2)35-15=20
3)20-15=5
non posso andare avanti...la seconda cifra decimale è 3 e il resto è di nuovo 5...questo ci porta a dire che d'ora in poi il numero sarà periodico e di periodo = 3.

quindi in definitiva il quoziente sarà dato da
7.53333...

chiaro ora?
ciao
il vecchio


vecchio1
anche il programma non è difficile da fare...basta che tu faccia due cicli concentrici...quello + interno fa il lavoro di conteggio e sottrazioni varie...quello più esterno regola il numero delle cifre decimali che vuoi ottenere...se hai bisogno di una mano chiedi pure...io so programmare solo in Pascal..ma alla fine sono tutti uguali..al limiti ti scrivo il programma in pseudo codifica...ok?
ciao e buon natale!!


tony19
ti ringrazio della pazienza e della disponibilità, vecchio;
ma, quando sei arrivato a calcolare (e il modo, scusa, era ovvio) la prima cifra decimale, che è un 5, come fai a "spostarla" sulla destra facendola diventare uno 0,5 per sommarla al 7?
e dopo, per il successivo 3 che deve diventare uno 0,03? etc.?

non stai facendo una -dannata- divisione per 10, come dicevo in un msg. precedente?

comunque, se posti lo schizzo della routine, te ne sarò grato, visto che 'sta divisione proprio non riesco a digerirla.

il tutto, come chiedevo, senza una tabella di costanti 1/10, 1/100, ..
. (e senza manipolazione di stringhe di caratteri alfanumerici che camuffi il lavoro di una divisione)

grazie ancora e buone feste.
tony

tony19
ti ringrazio della pazienza e della disponibilità, vecchio;
ma, quando sei arrivato a calcolare (e il modo, scusa, era ovvio) la prima cifra decimale, che è un 5, come fai a "spostarla" sulla destra facendola diventare uno 0,5 per sommarla al 7?
e dopo, per il successivo 3 che deve diventare uno 0,03? etc.?

non stai facendo una -dannata- divisione per 10, come dicevo in un msg. precedente?

comunque, se posti lo schizzo della routine, te ne sarò grato, visto che 'sta divisione proprio non riesco a digerirla.

il tutto, come chiedevo, senza una tabella di costanti 1/10, 1/100, ..
. (e senza manipolazione di stringhe di caratteri alfanumerici che camuffi il lavoro di una divisione)

grazie ancora e buone feste.
tony

vecchio1
aaaah...ora capisco dov'è il tuo problema!!! non era nella procedura del calcolo dei numeri dopo la virgola...ma di come raggiungere poi il risultato finale!!! eh eh..devo ammettere che non ci avevo pensato..ed è un bel problema se non vuoi usare un array...
fammici pensare un po' ok?


vecchio1
mm...e se il contatore ad ogni nuova iterazione venisse moltiplicato per 1/10?? neanche così ti soddisferebbe? in effetti così facendo non devi considerare nessun array..
ora penso al programma...
pazienta..



vecchio1
eh eh...ma quanto ero bravo col Pascal..mamma mia..mi spavento quasi... [;)]
ecco il listato del programma in Pascal...
program divisioni;
uses crt;
var  n,M,i:integer;
     d,p,q,quoz,koz,r:real;



begin
     clrscr;
     writeln('quante cifre dopo la virgola vuoi calcolare?');
     readln(M);
     writeln('scrivi il dividendo');
     readln(p);
     writeln('scrivi il divisore');
     readln(q);
     writeln('dunque la divisione da calcolare è la seguente:');
     writeln(p:10:M,' : ',q:10:M);
     r:=p;
     n:=0;
     d:=1;
     quoz:=0;
     while n<=M do
          begin

               i:=0;

               while r>=q do
                          begin
                             r:=r-q;
                             i:=i+1;
                          end;
               n:=n+1;
               r:=r*10;
               koz:=i*d;
               d:=d*(1/10);
               quoz:=quoz+koz;
          end;
     writeln('il risultato della divisione è ',quoz:10:M);
     readln
end.




vecchio1
sicuramente il programma può essere ottimizzato..ma non mi sono messo a studiarlo approfonditamente...visto che funziona!!

fammi sapere...

per ora ciao
il vecchio



vecchio1
mi era venuto il dubbio che il programma non funzionasse nel caso in cui il dividendo fosse minore del divisore...e invece no!! ho fatto proprio un ottimo lavoro!! [;)]
l'unica cosa forse da dover migliorare è che naturalmente non è previsto nessun arrotondamento...per cui di fatto si ottiene un troncamento del decimale...e non il suo arrotondamento...cmq...non credo sia difficile da risolvere...anzi...


vecchio1
ecco dunque il programma...leggermente modificato...in quetso modo è previsto anche l'arrotondamento!!!

program divisioni;
uses crt;
var  n,M,i:integer;
     d,p,q,quoz,koz,r:real;



begin
     clrscr;
     writeln('quante cifre dopo la virgola vuoi calcolare?');
     readln(M);
     writeln('scrivi il dividendo');
     readln(p);
     writeln('scrivi il divisore');
     readln(q);
     writeln('dunque la divisione da calcolare è la seguente:');
     writeln(p:10:M,' : ',q:10:M);
     r:=p;
     n:=0;
     d:=1;
     quoz:=0;
     while n<=M do
          begin

               i:=0;

               while r>=q do
                          begin
                             r:=r-q;
                             i:=i+1;
                          end;
               r:=r*10;
               if n=M then
                      begin
                          if i>=5 then i:=i+1;
                      end;
               koz:=i*d;
               d:=d*(1/10);
               n:=n+1;
               quoz:=quoz+koz;
          end;
     writeln('il risultato della divisione è ',quoz:10:M);
     readln
end.
 


beh...ora posso andare a dormire soddisfatto...fare ste cose mi galvanizza veramente..non vedo l'ora di iniziare programmazione all'università!! vedremo..

allora ciao!!
e...buon Santo Stefano... [;)]


tony19
vecchio, vorrei che tu e Drako ed io
fussimo ...
... d'accordo sul fatto che la "moltiplicazione per sole sottrazioni" che avevamo descritta funziona solo se il moltiplicatore è un intero.
la cosa non era stata sottolineata, ma sembrava evidente dai metodi descritti;
o mi sbaglio di grosso?

il tuo programma è bello assai, ma si fonda sul prodotto d:=d*(1/10), che dovrebbe esser risolto con una subroutine a base di sottrazioni.
si può fare?

vedi, nella soluz. all'esercizietto della "radice quadrata alla karl" con decimali, avevo aggirato l'ostacolo, non usando divisioni ma solo moltiplicazioni per interi, e partendo da una costante microscopica (pari, dapprima, con sporcizia di calcolo binario, a 10^-8 e poi, per evitare quella sporcizia, al quasi equivalente 2^-26, più "naturale" per la macchina);
cercavo però un metodo alternativo, basato su una moltiplicazione iniziale, il calcolo della radice intera, e una divisione finale (sempre ottenuta con sottrazioni)

accludo una variante del tuo prgm in cui ho sostituito le addizioni e le moltiplicazioni con le debite funzioni "a sola sottrazione".
tutte, tranne la moltiplicazione per 1/10 (forse ci troverai delle ingenuità, dovute alla mia ignoranza di pascal) .
se riesci a realizzare la funzione per quel prodotto, lo scopo è raggiunto.
program divisioni02;
uses wincrt;

var  n,M,i:integer; d,p,q,quoz,koz,r:real;

function addInt(a, b:integer): integer;
  begin addInt:= 0-(-a-b); end;

function addReal(a, b:real): real;
  begin addReal:= 0-(-a-b); end;

function multIntPerReal(a:integer; b:real): real;  {brutale}
  var i:integer; p:real;
  begin
    i:=a; p:=0;
    while i > 0 do begin p:=p-b; i:=i-1 end;
    MultIntPerReal:= 0 - p;
  end;

function multRealPerReal(a, b:real): real;
  begin {.......e' da realizzare !.......} end;

begin
  clrscr;
  writeln('quante cifre dopo la virgola vuoi calcolare?'); readln(M);
  writeln('scrivi il dividendo'); readln(p);
  writeln('scrivi il divisore'); readln(q);
  writeln('dunque la divisione da calcolare è la seguente:');
  writeln(p:10:M,' : ',q:10:M);
  r:=p; n:=0; d:=1; quoz:=0;
  while n<=M do
    begin
      i:=0;
      while r>=q do
        begin
          r:=r-q;
          i:=addInt(i, 1);
        end;
      r:=multIntPerReal(10, r);
      if ((n=M) and (i>=5)) then i:=addInt(i, 1);
      koz:=multIntPerReal(i, d);

      d:=d*(1/10); {QUI CI VORREBBE UNA multRealPerReal(d, 0.1)}

      n:= addInt(n ,1);
      quoz:=addReal(quoz, koz);
    end;
  writeln('il risultato della divisione è ',quoz:10:M);
  readln
end.

tony

vecchio1
ah..avevo capito, non avendo letto il post sulle radice quadrate, che tu avessi leggittimato l'operazione di moltiplicazione!! quindi ora il problema è ancora un altro!! definire la moltiplicazione usando solo sottrazioni!! (o solo somme a questo punto...visto che hai creato la funzione "add"...solo non ho capito perchè hai distinto addInt da addReal, quando bastava quest'ultima...forse per risparmiare sulla memoria?? questa parte della programmazione mi ha sempre lasciato un po' perplesso...il risparmio...mah...
cmq ora penso anche a questo problema...


Rispondi
Per rispondere a questa discussione devi prima effettuare il login.