<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Sviluppo Software &amp; Programmazione | RENOR &amp; Partners S.r.l.</title>
	<atom:link href="https://renor.it/blog/sviluppo-software-programmazione/feed/" rel="self" type="application/rss+xml" />
	<link>https://renor.it/blog/sviluppo-software-programmazione/</link>
	<description></description>
	<lastBuildDate>Sat, 19 Sep 2026 00:48:00 +0000</lastBuildDate>
	<language>it-IT</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=7.1.2</generator>
	<item>
		<title>Web App Custom: come scegliere l&#8217;azienda giusta in Italia per il tuo progetto</title>
		<link>https://renor.it/blog/sviluppo-software-programmazione/azienda-sviluppo-web-app-custom-italia/</link>
		
		<dc:creator><![CDATA[Simone Renzi]]></dc:creator>
		<pubDate>Tue, 08 Sep 2026 10:58:56 +0000</pubDate>
				<category><![CDATA[Sviluppo Software & Programmazione]]></category>
		<category><![CDATA[innovazione]]></category>
		<category><![CDATA[renor]]></category>
		<category><![CDATA[tecnologia]]></category>
		<category><![CDATA[trasformazione digitale]]></category>
		<guid isPermaLink="false">https://renor.it/blog/sviluppo-software-programmazione/azienda-sviluppo-web-app-custom-italia/</guid>

					<description><![CDATA[<p>Cerchi un'azienda sviluppo web app custom Italia affidabile? Scopri criteri, fasi e costi per scegliere il partner tecnologico giusto per il tuo progetto.</p>
<p>L'articolo <a href="https://renor.it/blog/sviluppo-software-programmazione/azienda-sviluppo-web-app-custom-italia/">Web App Custom: come scegliere l&#8217;azienda giusta in Italia per il tuo progetto</a> proviene da <a href="https://renor.it">RENOR &amp; Partners S.r.l.</a>.</p>
]]></description>
										<content:encoded><![CDATA[<h2 class="wp-block-heading">Cos&#039;è una web app custom (e perché non basta un software standard)</h2><p class="wp-block-paragraph">Se cerchi un&#039;azienda sviluppo web app custom Italia, devi prima capire cosa significa davvero &quot;su misura&quot;. Una web app custom è un&#039;applicazione accessibile dal browser. Viene sviluppata su misura per rispondere alle esigenze specifiche della tua azienda. A differenza di un software standard, che offre funzionalità già confezionate e uguali per tutti, la web app custom viene progettata attorno ai tuoi processi reali. Pensiamo al modo in cui gestisci gli ordini, segui i clienti, coordini il magazzino o produci i tuoi report.</p><p class="wp-block-paragraph">Il software standard ha vantaggi evidenti: costa meno all&#039;inizio, è pronto subito e viene aggiornato dal fornitore. Per molte attività di base è più che sufficiente. Il problema nasce quando l&#039;azienda deve piegare il proprio modo di lavorare al programma, invece del contrario. Infatti, ci si ritrova con funzioni che non servono. Si aggiungono passaggi manuali per colmare le lacune. Inoltre, gli strumenti diversi spesso non comunicano tra loro.</p><p class="wp-block-paragraph">Il custom conviene quando i tuoi processi sono un elemento distintivo o troppo specifici per un prodotto generalista. Ecco alcuni segnali concreti:</p><ul class="wp-block-list"><li>Usi più fogli Excel o strumenti scollegati per tenere insieme le informazioni.</li><li>Il gestionale attuale ti obbliga a lavori manuali ripetitivi ogni giorno.</li><li>Hai bisogno di integrare sistemi diversi in un unico flusso.</li><li>Il tuo modo di operare è un vantaggio competitivo che nessun software pronto replica.</li></ul><blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow"><p>La domanda giusta non è &quot;quanto costa&quot;, ma &quot;quanto mi sta già costando continuare a lavorare in modo inefficiente&quot;.</p></blockquote><p class="wp-block-paragraph">Va detto con onestà: il custom richiede un investimento maggiore. Inoltre, i tempi di realizzazione sono più lunghi. In cambio, però, ottieni uno strumento che cresce con te. Non paghi licenze per funzioni inutili. Inoltre, non devi cambiare il tuo modo di lavorare a ogni aggiornamento del fornitore.</p><p class="wp-block-paragraph">Un altro aspetto spesso trascurato è dove l&#039;applicazione vivrà. <a href="https://renor.it/servizi/sviluppo-e-cloud/">Sviluppo e cloud</a> vanno pensati insieme fin dall&#039;inizio. Infatti, un&#039;infrastruttura in cloud permette di far scalare la web app in base alla crescita. Inoltre, la rende accessibile ovunque e consente di gestire aggiornamenti e sicurezza in modo più flessibile. Scegliere il custom significa quindi decidere non solo cosa costruire, ma anche su quali basi tecniche appoggiarlo. Così eviti di ritrovarti limitato proprio quando l&#039;azienda inizia a correre.</p><h2 class="wp-block-heading">I segnali che la tua azienda ha bisogno di una web app su misura</h2><p class="wp-block-paragraph">Molte aziende continuano a lavorare con strumenti che non le rappresentano più. Spesso accade semplicemente perché il cambiamento sembra complesso o rischioso. Il problema, però, è che i sintomi di un sistema inadeguato raramente esplodono all&#039;improvviso. Invece, si accumulano giorno dopo giorno, sotto forma di ore perse, errori ricorrenti e decisioni prese senza dati affidabili. Riconoscerli in tempo è il primo passo per capire se un investimento in sviluppo su misura ha davvero senso per la tua realtà.</p><p class="wp-block-paragraph">Ecco alcuni segnali concreti che ricorrono spesso quando parliamo con imprenditori e responsabili operativi:</p><ul class="wp-block-list"><li>Il tuo team passa ore a copiare dati da un foglio Excel a un altro, oppure a compilare a mano gli stessi campi in più sistemi diversi.</li><li>Il gestionale che usate è rigido: per una modifica banale al flusso di lavoro servono workaround, plugin costosi o rinunce.</li><li>Le informazioni sono sparse tra email, fogli di calcolo, chat e software scollegati, quindi nessuno ha una visione unica e aggiornata.</li><li>Per ottenere un report affidabile qualcuno deve fermarsi mezza giornata a incrociare fonti diverse, spesso arrivando in ritardo rispetto alle decisioni.</li><li>Un processo chiave dipende da una singola persona che &quot;sa come si fa&quot;, con documentazione minima e alto rischio in caso di assenza.</li><li>Il volume di lavoro cresce, ma per gestirlo l&#039;unica soluzione sembra assumere altre persone da destinare ad attività ripetitive.</li></ul><p class="wp-block-paragraph">Se ti riconosci in tre o più di questi punti, probabilmente non hai un problema di persone. Piuttosto, hai un problema di strumenti che non seguono il modo in cui lavori davvero. È esattamente lo scenario in cui una web app custom porta valore: automatizza i passaggi manuali, centralizza i dati e adatta il software ai tuoi processi, non il contrario.</p><blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow"><p>La domanda non è &quot;possiamo continuare così?&quot;, ma &quot;quanto ci costa continuare così ogni mese?&quot;.</p></blockquote><p class="wp-block-paragraph">Tradurre questi segnali in una soluzione stabile richiede però competenze solide di sviluppo e cloud. Serve un&#039;applicazione pensata per il tuo processo, ospitata in modo affidabile e capace di crescere insieme alla tua azienda. È da qui che parte la scelta del partner giusto, il tema che affronteremo nelle prossime sezioni.</p><h2 class="wp-block-heading">Azienda sviluppo web app custom Italia: 7 criteri per valutarla</h2><figure class="wp-block-image size-large"><img fetchpriority="high" decoding="async" width="800" height="800" src="https://renor.it/wp-content/uploads/2026/09/web-app-custom-come-scegliere-lazienda-giusta-in-italia-per-il-tuo-progetto-fig-1-800x800.png" alt="Team di sviluppo software al lavoro su un progetto web app custom" class="wp-image-3173" srcset="https://renor.it/wp-content/uploads/2026/09/web-app-custom-come-scegliere-lazienda-giusta-in-italia-per-il-tuo-progetto-fig-1-800x800.png 800w, https://renor.it/wp-content/uploads/2026/09/web-app-custom-come-scegliere-lazienda-giusta-in-italia-per-il-tuo-progetto-fig-1-150x150.png 150w, https://renor.it/wp-content/uploads/2026/09/web-app-custom-come-scegliere-lazienda-giusta-in-italia-per-il-tuo-progetto-fig-1-300x300.png 300w" sizes="(max-width: 800px) 100vw, 800px" /></figure><p class="wp-block-paragraph">Scegliere il partner giusto è la decisione che determina il successo del progetto più delle tecnologie utilizzate. Per orientarti senza dover diventare un esperto tecnico, ecco sette criteri concreti da verificare prima di firmare un contratto con un&#039;azienda di sviluppo web app custom in Italia.</p><ul class="wp-block-list"><li>Competenze cloud reali: chiedi su quali infrastrutture lavorano abitualmente (ad esempio i principali provider) e come gestiscono scalabilità e continuità del servizio. Un&#039;azienda solida su sviluppo e cloud sa dimensionare la soluzione in base alla crescita prevista, senza costi sproporzionati a picchi occasionali.</li><li>Metodo di lavoro trasparente: verifica come organizzano il progetto in fasi, con quale frequenza mostrano avanzamenti e come raccolgono i tuoi feedback. Un metodo iterativo, con rilasci progressivi, riduce il rischio di scoprire problemi solo alla fine.</li><li>Manutenzione e supporto post-lancio: una web app non è un prodotto che si consegna e si dimentica. Chiedi cosa prevede il contratto dopo il rilascio, ad esempio aggiornamenti, correzioni, tempi di risposta e chi contattare in caso di problemi.</li><li>Sicurezza e protezione dei dati: informati su come proteggono gli accessi, dove risiedono i dati e come rispettano le normative sulla privacy. È un aspetto che tutela la tua azienda e i tuoi clienti.</li><li>Referenze verificabili: non fermarti al portfolio. Chiedi di parlare con clienti precedenti, meglio se dello stesso settore o con esigenze simili alle tue.</li><li>Chiarezza economica: preventivi dettagliati, con voci comprensibili e nessun costo nascosto. Diffida di cifre troppo basse, perché spesso nascondono lavoro non incluso.</li><li>Continuità e proprietà del codice: assicurati che il software sviluppato resti di tua proprietà. In caso di cambio fornitore, tutto deve essere documentato e trasferibile.</li></ul><p class="wp-block-paragraph">Un fornitore affidabile risponderà a queste domande con concretezza, senza vaghezze o promesse generiche. Se cerchi un&#039;azienda con competenze consolidate su sviluppo e cloud, capace di seguire il progetto dalla progettazione al mantenimento nel tempo, parlarne con noi è il primo passo per capire se c&#039;è la giusta sintonia.</p><blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow"><p>Il criterio più sottovalutato non è cosa sa fare oggi il fornitore, ma se sarà ancora al tuo fianco tra due anni.</p></blockquote><h2 class="wp-block-heading">Le fasi di un progetto di sviluppo custom, dall&#039;idea al rilascio</h2><p class="wp-block-paragraph">Un progetto di sviluppo su misura non parte mai direttamente dal codice. Segue invece un percorso ordinato, fatto di passaggi definiti. Questo percorso permette di trasformare un&#039;esigenza di business in uno strumento funzionante e affidabile. Conoscere queste fasi ti aiuta a capire cosa aspettarti, quando prendere decisioni e come misurare l&#039;avanzamento del lavoro.</p><p class="wp-block-paragraph">Ecco le tappe principali che un partner professionale ti proporrà:</p><ul class="wp-block-list"><li>Analisi: si parte dai tuoi obiettivi e dai processi reali dell&#039;azienda. In questa fase si definiscono le funzionalità prioritarie, i vincoli e i risultati attesi. È il momento in cui le idee diventano requisiti concreti.</li><li>Prototipazione: prima di scrivere il software, si costruiscono bozze e schermate navigabili. Vedere in anteprima come funzionerà la web app riduce i malintesi. Inoltre, permette di correggere la rotta quando i costi di modifica sono ancora bassi.</li><li>Sviluppo: qui prende forma il prodotto vero e proprio. Un buon fornitore lavora per fasi successive, rilasciando parti utilizzabili in modo incrementale. Così puoi vedere progressi tangibili senza aspettare la fine di tutto.</li><li>Test: ogni funzionalità viene verificata per garantire che faccia ciò che deve, anche in situazioni impreviste. I controlli riguardano correttezza, sicurezza e comportamento con volumi di dati realistici.</li><li>Deploy in cloud: la web app viene messa online su un&#039;infrastruttura affidabile, pronta a scalare quando cresce l&#039;utilizzo. Il rilascio in cloud garantisce accessibilità, aggiornamenti gestiti e continuità del servizio.</li></ul><p class="wp-block-paragraph">Il valore di questo percorso non sta solo nel prodotto finale, ma nella prevedibilità. Infatti, sai sempre a che punto sei, cosa è stato deciso e cosa resta da fare. In sintesi, ridurre l&#039;incertezza significa ridurre il rischio del tuo investimento.</p><blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow"><p>Un progetto ben gestito non è quello senza imprevisti, ma quello in cui gli imprevisti emergono presto e si affrontano con metodo.</p></blockquote><p class="wp-block-paragraph">È proprio in questo che si concentra il nostro servizio di Sviluppo e cloud: accompagnare il progetto dalla progettazione fino al rilascio online. Il percorso strutturato tiene insieme costruzione del software e messa in produzione su infrastruttura cloud. Così la tua idea non resta un file di specifiche, ma diventa uno strumento operativo e disponibile agli utenti.</p><h2 class="wp-block-heading">Quanto costa e quanto tempo richiede una web app custom</h2><figure class="wp-block-image size-large"><img decoding="async" width="800" height="800" src="https://renor.it/wp-content/uploads/2026/09/web-app-custom-come-scegliere-lazienda-giusta-in-italia-per-il-tuo-progetto-fig-2-800x800.png" alt="Consulenza tra imprenditore e specialista IT per un progetto di web app su misura" class="wp-image-3174" srcset="https://renor.it/wp-content/uploads/2026/09/web-app-custom-come-scegliere-lazienda-giusta-in-italia-per-il-tuo-progetto-fig-2-800x800.png 800w, https://renor.it/wp-content/uploads/2026/09/web-app-custom-come-scegliere-lazienda-giusta-in-italia-per-il-tuo-progetto-fig-2-150x150.png 150w, https://renor.it/wp-content/uploads/2026/09/web-app-custom-come-scegliere-lazienda-giusta-in-italia-per-il-tuo-progetto-fig-2-300x300.png 300w" sizes="(max-width: 800px) 100vw, 800px" /></figure><p class="wp-block-paragraph">È la domanda che ogni imprenditore si pone per primo, ed è legittima. La risposta onesta è: dipende. Non per evasività, ma perché una web app su misura non è un prodotto a scaffale con un listino fisso. Il costo e i tempi variano in base a diversi fattori. Tra questi troviamo la complessità delle funzionalità, il numero di integrazioni con sistemi esterni, la mole di dati da gestire e il livello di personalizzazione dell&#039;interfaccia. Detto questo, esistono criteri concreti per farsi un&#039;idea realistica prima ancora di chiedere un preventivo.</p><p class="wp-block-paragraph">In linea di massima, sul mercato italiano un progetto può collocarsi in tre fasce indicative:</p><ul class="wp-block-list"><li>Progetto contenuto (MVP o gestionale semplice): tra qualche migliaio e 15-20 mila euro, con tempi di 1-3 mesi. Utile per validare un&#039;idea o coprire un singolo processo aziendale.</li><li>Progetto medio (più moduli, ruoli utente, integrazioni): tra 20 e 60 mila euro, con tempi di 3-6 mesi. È la fascia più comune per le PMI che digitalizzano un flusso di lavoro reale.</li><li>Progetto ampio (piattaforma complessa, alta scalabilità, molte integrazioni): oltre i 60 mila euro e tempi che possono superare i 6-12 mesi.</li></ul><p class="wp-block-paragraph">Questi numeri servono a orientarsi, non a preventivare: solo un&#039;analisi dei tuoi requisiti restituisce una stima affidabile. Un errore frequente è ragionare solo sul costo iniziale. Infatti, una web app va ospitata, mantenuta e aggiornata nel tempo. Qui entrano in gioco le spese ricorrenti di infrastruttura cloud, monitoraggio e manutenzione, spesso sottovalutate. È proprio l&#039;ambito del nostro servizio di sviluppo e cloud, che affianca la realizzazione dell&#039;applicazione alla gestione dell&#039;ambiente su cui gira, evitando sorprese dopo il rilascio.</p><blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow"><p>Un preventivo troppo basso e troppo veloce raramente è un affare: spesso significa requisiti non compresi o costi che riemergeranno più avanti.</p></blockquote><p class="wp-block-paragraph">Il modo migliore per ridurre l&#039;incertezza è partire con un confronto sui tuoi obiettivi concreti. Da lì, budget e tempistiche smettono di essere numeri astratti. Diventano invece un piano su cui decidere con serenità. Se hai un&#039;esigenza in mente, richiedere un preventivo è il primo passo per trasformarla in una stima misurabile.</p><h2 class="wp-block-heading">Perché scegliere RENOR &amp; Partners come azienda per lo sviluppo della tua web app custom</h2><p class="wp-block-paragraph">Dopo aver visto quali criteri usare per scegliere un fornitore e come si articola un progetto, resta una domanda concreta: a chi affidarsi davvero. RENOR &amp; Partners nasce per accompagnare PMI e professionisti in percorsi digitali che partono da esigenze reali, non da soluzioni preconfezionate. L&#039;obiettivo non è venderti codice, ma costruire uno strumento che semplifichi il lavoro quotidiano e sostenga la crescita dell&#039;azienda nel tempo.</p><p class="wp-block-paragraph">Il nostro servizio di Sviluppo e cloud si occupa della realizzazione della web app su misura e della sua messa in esercizio in un ambiente affidabile e scalabile. Questo significa che non ti limiti ad avere un&#039;applicazione funzionante. Hai anche un&#039;infrastruttura pensata per crescere con te, senza dover ripensare tutto quando aumentano gli utenti o i dati da gestire.</p><p class="wp-block-paragraph">A monte dello sviluppo, la nostra attività di <a href="https://renor.it/servizi/consulenza-it/">Consulenza IT</a> ti aiuta a mettere ordine nelle priorità prima di scrivere una riga di codice. È la fase in cui trasformiamo un&#039;idea o un problema operativo in un progetto chiaro, con obiettivi misurabili e scelte tecniche motivate. Per chi non ha competenze tecniche interne, questo passaggio evita errori costosi e decisioni prese sull&#039;onda dell&#039;entusiasmo.</p><p class="wp-block-paragraph">Concretamente, lavorare con noi significa avere accanto un partner che parla il tuo linguaggio. Spieghiamo ogni scelta e ti coinvolgiamo nelle decisioni che contano. Ecco cosa puoi aspettarti:</p><ul class="wp-block-list"><li>Un interlocutore che traduce gli obiettivi di business in requisiti tecnici chiari</li><li>Sviluppo su misura e messa in cloud pensati per affidabilità e scalabilità</li><li>Un percorso trasparente, dalla consulenza iniziale al rilascio</li><li>Attenzione alle esigenze specifiche di PMI e professionisti, senza sovradimensionare</li></ul><p class="wp-block-paragraph">Se stai valutando una web app custom e vuoi capire se è la scelta giusta per te, il modo migliore per iniziare è confrontarsi su obiettivi, tempi e budget. Prenota una <a href="https://renor.it/servizi/consulenza-strategica/">consulenza strategica</a> con RENOR &amp; Partners, l&#039;azienda di sviluppo web app custom in Italia su cui puoi contare: analizziamo insieme la tua situazione e definiamo il primo passo concreto, senza impegno.</p>

<div class="wp-block-group scriba-cta"><div class="wp-block-group__inner-container is-layout-flow wp-block-group-is-layout-flow"><p><strong>Ti serve un supporto concreto?</strong> Scopri il nostro servizio <a href="https://renor.it/servizi/sviluppo-e-cloud/">Sviluppo e cloud</a> oppure <a href="https://renor.it/contatti/">contattaci</a> per una consulenza.</p></div></div><p>L'articolo <a href="https://renor.it/blog/sviluppo-software-programmazione/azienda-sviluppo-web-app-custom-italia/">Web App Custom: come scegliere l&#8217;azienda giusta in Italia per il tuo progetto</a> proviene da <a href="https://renor.it">RENOR &amp; Partners S.r.l.</a>.</p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>ERP personalizzato &#8211; Come realizzare un gestionale su misura per la tua azienda</title>
		<link>https://renor.it/blog/sviluppo-software-programmazione/realizzazione-gestionale-erp-personalizzato-azienda/</link>
		
		<dc:creator><![CDATA[Simone Renzi]]></dc:creator>
		<pubDate>Mon, 07 Sep 2026 11:09:06 +0000</pubDate>
				<category><![CDATA[Sviluppo Software & Programmazione]]></category>
		<category><![CDATA[automazione]]></category>
		<category><![CDATA[innovazione]]></category>
		<category><![CDATA[renor]]></category>
		<category><![CDATA[trasformazione digitale]]></category>
		<guid isPermaLink="false">https://renor.it/blog/sviluppo-software-programmazione/realizzazione-gestionale-erp-personalizzato-azienda/</guid>

					<description><![CDATA[<p>Scopri come funziona la realizzazione gestionale ERP personalizzato azienda: fasi, moduli, costi e vantaggi di un sistema su misura per il tuo business.</p>
<p>L'articolo <a href="https://renor.it/blog/sviluppo-software-programmazione/realizzazione-gestionale-erp-personalizzato-azienda/">ERP personalizzato &#8211; Come realizzare un gestionale su misura per la tua azienda</a> proviene da <a href="https://renor.it">RENOR &amp; Partners S.r.l.</a>.</p>
]]></description>
										<content:encoded><![CDATA[<h2 class="wp-block-heading">ERP standard o realizzazione gestionale ERP personalizzato azienda: qual è la differenza</h2><p class="wp-block-paragraph">La realizzazione gestionale ERP personalizzato azienda parte da un sistema informatico che raccoglie in un unico ambiente i processi aziendali: vendite, acquisti, magazzino, contabilità, produzione, gestione del personale. Infatti, l&#039;obiettivo è far dialogare informazioni che spesso vivono separate in fogli di calcolo, e-mail e programmi diversi. In questo modo hai una visione coerente e aggiornata di ciò che accade in azienda.</p><p class="wp-block-paragraph">La differenza tra un ERP standard e un gestionale su misura sta nel punto di partenza. L&#039;ERP pacchettizzato è un prodotto già confezionato: offre funzioni valide per molte imprese, ma chiede a te di adattare il modo di lavorare al software. Invece, la realizzazione gestionale ERP personalizzato azienda fa il percorso inverso: parte dai tuoi processi reali e costruisce gli strumenti attorno ad essi, includendo solo ciò che serve davvero.</p><p class="wp-block-paragraph">Per capire quale strada valutare, aiuta osservare alcune differenze concrete:</p><ul class="wp-block-list"><li>Adattamento: lo standard impone i suoi flussi; il su misura segue i tuoi.</li><li>Funzioni: il pacchetto include voci che potresti non usare mai; il personalizzato copre esattamente le tue esigenze.</li><li>Evoluzione: un gestionale su misura cresce insieme all&#039;azienda, integrandosi con gli strumenti che già utilizzi.</li><li>Vantaggio competitivo: se una procedura è il tuo punto di forza, un software su misura la valorizza invece di appiattirla su uno schema generico.</li></ul><p class="wp-block-paragraph">Non esiste una scelta giusta in assoluto. Un&#039;azienda con processi lineari può trovare nell&#039;ERP pacchettizzato una soluzione rapida ed economica. Invece, chi ha flussi specifici o vuole trasformare le proprie procedure in un vantaggio difficilmente replicabile trae maggior beneficio da un percorso di sviluppo su misura.</p><blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow"><p>La domanda non è solo &quot;quale software mi serve&quot;, ma &quot;chi si adatta a chi&quot;: io al programma, o il programma a me?</p></blockquote><p class="wp-block-paragraph">È qui che entra in gioco un lavoro di <a href="https://renor.it/servizi/sviluppo-e-cloud/">sviluppo e cloud</a>: costruire un gestionale progettato sulla realtà dell&#039;azienda e reso accessibile in modo sicuro, ovunque e in ogni momento. Nei prossimi paragrafi vedremo come si arriva concretamente a una soluzione di questo tipo.</p><h2 class="wp-block-heading">Quando conviene davvero un ERP personalizzato (e quando no)</h2><p class="wp-block-paragraph">La domanda giusta non è &quot;un gestionale su misura è meglio?&quot;, ma &quot;la mia azienda ha esigenze che un software standard non riesce a coprire?&quot;. Nella maggior parte dei casi, la risposta dipende da quanto i tuoi processi si discostano da ciò che il mercato offre già pronto. Se lavori in modo lineare e comune al tuo settore, una soluzione standard è spesso più veloce ed economica. Se invece il tuo modo di operare è parte del tuo vantaggio competitivo, forzarlo dentro uno schema preconfezionato rischia di rallentarti.</p><p class="wp-block-paragraph">Ci sono tre segnali concreti che indicano quando la realizzazione gestionale ERP personalizzato azienda ripaga davvero l&#039;investimento.</p><ul class="wp-block-list"><li>Processi non standard: se i tuoi flussi di lavoro (produzione, logistica, gestione ordini, controllo qualità) seguono logiche particolari e oggi li reggi con fogli Excel, email o passaggi manuali, un ERP costruito attorno a questi processi elimina errori e tempi morti.</li><li>Integrazioni specifiche: se hai bisogno che il gestionale dialoghi con macchinari, e-commerce, portali dei clienti, corrieri o software già in uso, un progetto su misura può essere pensato per queste connessioni fin dall&#039;inizio, invece di adattarti a integrazioni limitate.</li><li>Crescita rapida o modello in evoluzione: se stai scalando, aprendo nuove sedi o cambiando modello di business, ti serve uno strumento che cresca con te e non un vincolo da rifare tra due anni.</li></ul><p class="wp-block-paragraph">Al contrario, un ERP personalizzato è spesso una spesa poco giustificata quando i volumi sono ridotti e i processi sono semplici e replicabili. Lo stesso vale quando l&#039;azienda non è ancora pronta a definire con chiarezza come lavora. In questi casi conviene partire da una soluzione standard e valutare la personalizzazione solo dove emergono limiti reali.</p><blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow"><p>La regola pratica: personalizza ciò che ti differenzia, standardizza ciò che è comune a tutti.</p></blockquote><p class="wp-block-paragraph">Se riconosci la tua azienda in uno di questi segnali, il passo successivo è capire come impostare il progetto. Qui entrano in gioco competenze di sviluppo e cloud, che permettono di realizzare un gestionale disegnato sui tuoi processi e accessibile in modo sicuro da più sedi e dispositivi, seguendo l&#039;evoluzione del tuo business nel tempo.</p><h2 class="wp-block-heading">Le fasi di realizzazione di un gestionale ERP su misura</h2><p class="wp-block-paragraph">Realizzare un ERP personalizzato non significa &quot;scrivere codice&quot; fin dal primo giorno. È infatti un percorso strutturato, in cui ogni fase riduce l&#039;incertezza e costruisce le basi per quella successiva. Conoscere questi passaggi ti permette di capire cosa aspettarti, quali decisioni spettano a te e come tenere sotto controllo tempi e budget.</p><h2 class="wp-block-heading">1. Analisi dei processi</h2><p class="wp-block-paragraph">Tutto parte dal capire come lavora davvero la tua azienda: flussi, ruoli, punti critici e attività ripetitive che oggi fanno perdere tempo. In questa fase si raccolgono le esigenze di chi userà il software ogni giorno. L&#039;obiettivo non è replicare le abitudini esistenti, ma individuare cosa migliorare e cosa automatizzare.</p><h2 class="wp-block-heading">2. Progettazione</h2><p class="wp-block-paragraph">Le informazioni raccolte diventano un progetto concreto: quali moduli servono, come devono comunicare tra loro e come sarà l&#039;esperienza d&#039;uso. Definire in anticipo funzionalità e priorità evita sorprese. Inoltre, permette di stimare con precisione risorse e tempi di rilascio.</p><h2 class="wp-block-heading">3. Sviluppo</h2><figure class="wp-block-image size-large"><img decoding="async" width="800" height="800" src="https://renor.it/wp-content/uploads/2026/09/erp-personalizzato-come-realizzare-un-gestionale-su-misura-per-la-tua-azienda-fig-1-800x800.png" alt="Team di sviluppo al lavoro su un gestionale ERP personalizzato" class="wp-image-3150" srcset="https://renor.it/wp-content/uploads/2026/09/erp-personalizzato-come-realizzare-un-gestionale-su-misura-per-la-tua-azienda-fig-1-800x800.png 800w, https://renor.it/wp-content/uploads/2026/09/erp-personalizzato-come-realizzare-un-gestionale-su-misura-per-la-tua-azienda-fig-1-150x150.png 150w, https://renor.it/wp-content/uploads/2026/09/erp-personalizzato-come-realizzare-un-gestionale-su-misura-per-la-tua-azienda-fig-1-300x300.png 300w" sizes="(max-width: 800px) 100vw, 800px" /></figure><p class="wp-block-paragraph">È la fase in cui il gestionale prende forma. Un approccio efficace prevede rilasci progressivi: si costruiscono prima le funzioni essenziali, così puoi vederle funzionare e dare feedback. Quindi, non devi aspettare mesi per un prodotto finito. In questo ambito si inserisce il nostro servizio di sviluppo e cloud, pensato per costruire soluzioni su misura e renderle accessibili in modo affidabile.</p><h2 class="wp-block-heading">4. Integrazione</h2><p class="wp-block-paragraph">Un ERP raramente vive da solo. Va collegato agli strumenti che già utilizzi, in modo che i dati fluiscano senza doppie digitazioni. Una buona integrazione è ciò che trasforma il gestionale in un vero centro di controllo dell&#039;azienda.</p><h2 class="wp-block-heading">5. Test e rilascio</h2><p class="wp-block-paragraph">Prima di andare in produzione, il sistema viene verificato in condizioni reali per correggere errori e affinare i dettagli. Il rilascio è accompagnato dalla formazione delle persone, così che l&#039;adozione sia rapida. Non è un punto di arrivo: un ERP su misura evolve nel tempo insieme all&#039;azienda.</p><blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow"><p>Un metodo chiaro, fatto di fasi distinte e verificabili, è la prima garanzia contro imprevisti, costi fuori controllo e progetti che non arrivano mai al traguardo.</p></blockquote><h2 class="wp-block-heading">Moduli e integrazioni: dal magazzino al CRM</h2><p class="wp-block-paragraph">Il vero valore della realizzazione gestionale ERP personalizzato azienda sta nella capacità di far dialogare tra loro le diverse aree dell&#039;azienda. Invece di gestire informazioni sparse tra fogli di calcolo, software separati e caselle di posta, un gestionale su misura raccoglie i dati in un unico ambiente coerente. Ogni modulo copre una funzione specifica, ma tutti condividono le stesse informazioni aggiornate in tempo reale.</p><p class="wp-block-paragraph">Un ERP viene costruito componendo i moduli realmente utili alla tua realtà, senza pagare funzioni che non userai mai. Ecco le aree più richieste dalle PMI:</p><ul class="wp-block-list"><li>Magazzino e logistica: giacenze, movimentazioni, riordini automatici e tracciabilità dei lotti, per sapere sempre cosa hai e dove si trova.</li><li>Acquisti e fornitori: gestione ordini, scadenze e listini, con storico completo delle forniture.</li><li>Vendite e fatturazione: preventivi, ordini clienti, documenti di trasporto e fatture, collegati direttamente alla contabilità.</li><li>Produzione: distinte base, avanzamento delle lavorazioni e calcolo dei costi effettivi.</li><li>Reportistica e cruscotti: indicatori chiave sempre a portata di mano per decidere con dati concreti.</li></ul><p class="wp-block-paragraph">La forza di un sistema su misura emerge quando questi moduli si integrano con gli strumenti che già utilizzi: portale e-commerce, fatturazione elettronica, gestionale contabile del commercialista o piattaforme di spedizione. Infatti, un&#039;integrazione ben progettata elimina il doppio inserimento dei dati e riduce gli errori manuali che rallentano il lavoro quotidiano.</p><p class="wp-block-paragraph">Tra le integrazioni più strategiche c&#039;è quella con il CRM, il modulo dedicato alla relazione con i clienti. Collegare anagrafiche, ordini e comunicazioni permette al reparto commerciale di vedere in un colpo d&#039;occhio lo storico di ogni cliente: acquisti, offerte in corso, richieste di assistenza e scadenze. Per una PMI, un CRM su misura significa gestire la relazione con criteri concreti e coerenti con i propri processi, non adattarsi a un software rigido pensato per altri.</p><p class="wp-block-paragraph">Rendere tutto questo accessibile in modo affidabile è una questione di infrastruttura. Con un approccio orientato allo sviluppo e al cloud, i moduli e le integrazioni del tuo ERP possono essere disponibili ovunque e in sicurezza. Così, chi lavora in sede, in trasferta o da remoto può operare sugli stessi dati aggiornati.</p><h2 class="wp-block-heading">Quanto costa e come stimare il budget di un ERP su misura</h2><figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="800" height="800" src="https://renor.it/wp-content/uploads/2026/09/erp-personalizzato-come-realizzare-un-gestionale-su-misura-per-la-tua-azienda-fig-2-800x800.png" alt="Consulenza per la realizzazione di un ERP su misura in azienda" class="wp-image-3151" srcset="https://renor.it/wp-content/uploads/2026/09/erp-personalizzato-come-realizzare-un-gestionale-su-misura-per-la-tua-azienda-fig-2-800x800.png 800w, https://renor.it/wp-content/uploads/2026/09/erp-personalizzato-come-realizzare-un-gestionale-su-misura-per-la-tua-azienda-fig-2-150x150.png 150w, https://renor.it/wp-content/uploads/2026/09/erp-personalizzato-come-realizzare-un-gestionale-su-misura-per-la-tua-azienda-fig-2-300x300.png 300w" sizes="auto, (max-width: 800px) 100vw, 800px" /></figure><p class="wp-block-paragraph">È la domanda che ogni imprenditore si pone per prima, ma non esiste un listino con un prezzo fisso. Un ERP su misura non è un prodotto da scaffale: è un progetto che viene costruito attorno ai processi della tua azienda. Per questo il budget si stima, non si legge da un catalogo. La buona notizia è che i fattori che determinano il costo sono chiari e prevedibili. Conoscerli ti permette di ragionare con cognizione di causa fin dal primo confronto con un fornitore.</p><p class="wp-block-paragraph">Il costo dipende essenzialmente dalla complessità di ciò che vuoi automatizzare. Infatti, più i tuoi processi sono articolati o specifici, più aumenta il lavoro di analisi e di sviluppo. Ecco le voci che pesano di più su un preventivo:</p><ul class="wp-block-list"><li>Numero e complessità dei moduli richiesti (magazzino, CRM, produzione, contabilità): ogni area aggiunge logiche e sviluppo dedicato.</li><li>Integrazioni con software e sistemi già in uso: collegare gestionali, e-commerce o strumenti esterni richiede lavoro tecnico su misura.</li><li>Grado di personalizzazione dei flussi di lavoro rispetto a soluzioni standard.</li><li>Numero di utenti e ruoli con permessi e viste differenti.</li><li>Migrazione dei dati storici dai sistemi attuali, spesso sottovalutata ma decisiva.</li><li>Manutenzione, aggiornamenti e assistenza dopo il rilascio.</li></ul><p class="wp-block-paragraph">Un altro elemento che incide sui costi, spesso in modo positivo, è la scelta dell&#039;infrastruttura. Un approccio basato su sviluppo e cloud consente di evitare investimenti iniziali importanti in server e hardware. Inoltre, distribuisce la spesa nel tempo e adatta le risorse alla crescita reale dell&#039;azienda. In pratica paghi ciò che usi, con maggiore flessibilità sia in fase di avvio sia negli anni successivi.</p><blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow"><p>Il vero costo di un ERP non è solo lo sviluppo iniziale, ma il totale su tre-cinque anni: sviluppo, manutenzione, evoluzione e infrastruttura.</p></blockquote><p class="wp-block-paragraph">Per costruire una stima affidabile, il consiglio è partire da un&#039;analisi dei processi prioritari e definire un primo perimetro contenuto, da ampliare in modo graduale. Un progetto avviato per fasi permette di controllare l&#039;investimento e vedere risultati concreti prima di impegnare l&#039;intero budget. Per approfondire tutte le voci di spesa nel dettaglio, ti rimandiamo alla nostra guida completa ai costi di un progetto software aziendale.</p><h2 class="wp-block-heading">Cloud, sicurezza e manutenzione nel tempo</h2><p class="wp-block-paragraph">Un gestionale su misura non è un progetto che si conclude alla consegna: è uno strumento che accompagna l&#039;azienda per anni. Per questo l&#039;infrastruttura su cui gira e le attività che ne garantiscono la continuità contano quanto le funzionalità stesse. Infatti, un ERP costruito bene ma ospitato male, o lasciato senza aggiornamenti, diventa presto un rischio invece che un vantaggio.</p><p class="wp-block-paragraph">Ospitare il gestionale in cloud significa non doversi preoccupare della gestione di server fisici, ridurre i costi iniziali di hardware e poter adeguare le risorse alla crescita dell&#039;azienda. Se aumentano gli utenti, le sedi o i volumi di dati, l&#039;infrastruttura si scala senza dover ripensare tutto da capo. Inoltre, l&#039;accesso da più postazioni e in mobilità diventa naturale: un aspetto essenziale per chi lavora su cantieri, filiali o con collaboratori esterni.</p><h2 class="wp-block-heading">La sicurezza non è un optional</h2><p class="wp-block-paragraph">Il gestionale contiene i dati più sensibili dell&#039;azienda: anagrafiche clienti, prezzi, margini, magazzino. Proteggerli significa mettere in campo alcune misure di base che dovrebbero sempre essere previste nel progetto.</p><ul class="wp-block-list"><li>Backup regolari e automatici, con la possibilità concreta di ripristinare i dati in caso di problemi</li><li>Accessi controllati per ruolo, così ogni persona vede solo ciò che le compete</li><li>Aggiornamenti tempestivi per correggere vulnerabilità e mantenere il sistema affidabile</li><li>Monitoraggio dell&#039;infrastruttura per intervenire prima che un problema blocchi il lavoro</li></ul><p class="wp-block-paragraph">La manutenzione nel tempo va poi oltre la sola sicurezza. Le normative cambiano, i processi aziendali evolvono, nascono nuove esigenze. Per questo un gestionale su misura deve poter crescere insieme all&#039;impresa, con evoluzioni pianificate e non improvvisate. Avere un partner che segue sia lo sviluppo sia il cloud evita il classico rimpallo tra chi ha scritto il software e chi gestisce i server, riducendo tempi di intervento e responsabilità poco chiare.</p><blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow"><p>Con il nostro servizio di Sviluppo e cloud seguiamo il gestionale in modo continuativo: dalla realizzazione all&#039;infrastruttura che lo ospita, così hai un unico riferimento nel tempo.</p></blockquote><p class="wp-block-paragraph">In pratica, valutare fin dall&#039;inizio dove e come vivrà il gestionale, e chi se ne prenderà cura negli anni, è parte integrante di un progetto ben fatto. Questo è ciò che trasforma un buon software in uno strumento su cui contare ogni giorno.</p><h2 class="wp-block-heading">Come RENOR &amp; Partners realizza il tuo ERP personalizzato</h2><p class="wp-block-paragraph">Dopo aver visto fasi, moduli, budget e gestione nel tempo, resta la domanda più concreta: a chi affidare un progetto così importante? Il valore di un ERP su misura non dipende solo dal codice, ma dal metodo con cui viene costruito. Dipende anche dalla capacità di tradurre i processi reali della tua azienda in uno strumento che li semplifica davvero.</p><p class="wp-block-paragraph">Il nostro approccio parte dall&#039;ascolto. Prima di scrivere una sola riga di software, dedichiamo tempo a capire come lavori oggi: dove si perde tempo, quali dati vengono duplicati, quali passaggi generano errori. Solo così è possibile progettare un gestionale che si adatta alla tua organizzazione, e non il contrario.</p><p class="wp-block-paragraph">Con il nostro servizio di Sviluppo e cloud accompagniamo l&#039;azienda lungo tutto il percorso, senza lasciarla sola nei momenti più delicati.</p><ul class="wp-block-list"><li>Analisi dei processi: mappiamo insieme flussi, ruoli e priorità per definire cosa serve davvero e cosa può attendere una fase successiva.</li><li>Sviluppo su misura: costruiamo le funzionalità in modo modulare, così puoi partire dall&#039;essenziale e far crescere il gestionale nel tempo.</li><li>Cloud e continuità: rendiamo l&#039;ERP accessibile in modo sicuro, con un&#039;infrastruttura pensata per affidabilità e disponibilità dei dati.</li><li>Supporto continuo: restiamo al tuo fianco anche dopo il rilascio, per aggiornamenti, evoluzioni e assistenza.</li></ul><p class="wp-block-paragraph">Questo significa niente sorprese e nessuna dipendenza da soluzioni rigide. Ogni scelta tecnica viene spiegata in modo comprensibile, perché sei tu a decidere le priorità del progetto in base agli obiettivi di business.</p><blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow"><p>Un buon ERP non si vede: si nota solo perché ogni giornata di lavoro diventa più semplice e ordinata.</p></blockquote><p class="wp-block-paragraph">Se stai valutando la realizzazione gestionale ERP personalizzato azienda per la tua impresa, il modo migliore per iniziare è confrontarti con chi lo realizza ogni giorno. Contattaci per una consulenza tramite la pagina dedicata al nostro servizio di Sviluppo e cloud: analizzeremo insieme la tua situazione e ti aiuteremo a capire, senza impegno, se un ERP personalizzato è la scelta giusta e da dove conviene partire.</p>

<div class="wp-block-group scriba-cta"><div class="wp-block-group__inner-container is-layout-flow wp-block-group-is-layout-flow"><p><strong>Ti serve un supporto concreto?</strong> Scopri il nostro servizio <a href="https://renor.it/servizi/sviluppo-e-cloud/">Sviluppo e cloud</a> oppure <a href="https://renor.it/contatti/">contattaci</a> per una consulenza.</p></div></div>

<h2 class="wp-block-heading">Leggi anche</h2>

<ul class="wp-block-list"><li><a href="https://renor.it/blog/sviluppo-software-programmazione/sviluppo-crm-su-misura-per-pmi/">Sviluppo CRM su misura per PMI: quando conviene e cosa valutare</a></li><li><a href="https://renor.it/blog/sviluppo-software-programmazione/preventivo-sviluppo-applicazione-web-aziendale/">Preventivo per lo sviluppo di un&#8217;applicazione web aziendale: guida completa ai costi</a></li></ul><p>L'articolo <a href="https://renor.it/blog/sviluppo-software-programmazione/realizzazione-gestionale-erp-personalizzato-azienda/">ERP personalizzato &#8211; Come realizzare un gestionale su misura per la tua azienda</a> proviene da <a href="https://renor.it">RENOR &amp; Partners S.r.l.</a>.</p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Sviluppo CRM su misura per PMI: quando conviene e cosa valutare</title>
		<link>https://renor.it/blog/sviluppo-software-programmazione/sviluppo-crm-su-misura-per-pmi/</link>
		
		<dc:creator><![CDATA[Simone Renzi]]></dc:creator>
		<pubDate>Sun, 06 Sep 2026 10:47:16 +0000</pubDate>
				<category><![CDATA[Sviluppo Software & Programmazione]]></category>
		<category><![CDATA[automazione]]></category>
		<category><![CDATA[renor]]></category>
		<category><![CDATA[renor & partners]]></category>
		<category><![CDATA[trasformazione digitale]]></category>
		<guid isPermaLink="false">https://renor.it/blog/sviluppo-software-programmazione/sviluppo-crm-su-misura-per-pmi/</guid>

					<description><![CDATA[<p>Scopri come funziona lo sviluppo CRM su misura per PMI: quando conviene, quali costi prevedere e i fattori chiave per una scelta consapevole.</p>
<p>L'articolo <a href="https://renor.it/blog/sviluppo-software-programmazione/sviluppo-crm-su-misura-per-pmi/">Sviluppo CRM su misura per PMI: quando conviene e cosa valutare</a> proviene da <a href="https://renor.it">RENOR &amp; Partners S.r.l.</a>.</p>
]]></description>
										<content:encoded><![CDATA[<h2 class="wp-block-heading">Sviluppo CRM su misura per PMI: soluzione pronta o su misura?</h2><p class="wp-block-paragraph">Lo sviluppo CRM su misura per PMI è un tema che riguarda sempre più aziende. Un CRM (Customer Relationship Management) è lo strumento con cui un&#039;azienda raccoglie e organizza le informazioni sui clienti. Anagrafiche, trattative, offerte, storico degli acquisti e attività da svolgere trovano posto in un unico sistema. In pratica, sostituisce fogli di calcolo sparsi, appunti personali e caselle email dove le informazioni si perdono. L&#039;obiettivo è semplice: sapere sempre a che punto è ogni cliente, senza lasciare opportunità per strada.</p><p class="wp-block-paragraph">Sul mercato esistono due strade principali. La prima è il software pronto all&#039;uso: soluzioni preconfezionate, disponibili in abbonamento, che si attivano in tempi rapidi. Coprono le esigenze più diffuse ma restano generiche. La seconda strada è lo sviluppo su misura: un CRM costruito attorno ai processi specifici della tua azienda, ai tuoi flussi di vendita e al modo in cui lavorano davvero le persone.</p><p class="wp-block-paragraph">Nessuna delle due opzioni è migliore in assoluto: dipende da come lavori. Per capire da che parte stai, valuta questi elementi:</p><ul class="wp-block-list"><li>I tuoi processi commerciali sono standard o hanno passaggi particolari che nessun software generico riesce a rappresentare?</li><li>Ti ritrovi a piegare il modo di lavorare del tuo team per adattarlo allo strumento, invece del contrario?</li><li>Hai bisogno di collegare il CRM ad altri sistemi già in uso, come gestionale, e-commerce o fatturazione?</li><li>Paghi canoni per funzioni che non usi, oppure ti mancano funzioni che ti servirebbero ogni giorno?</li><li>Prevedi di crescere e temi che la soluzione attuale diventi presto un limite?</li></ul><p class="wp-block-paragraph">Se la maggior parte delle risposte fa emergere vincoli e compromessi, allora una soluzione standard potrebbe non bastare. Al contrario, se i tuoi processi sono lineari e comuni, un prodotto pronto è spesso la scelta più rapida e conveniente.</p><blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow"><p>La domanda giusta non è &quot;qual è il CRM migliore&quot;, ma &quot;qual è il CRM giusto per come lavora la mia azienda&quot;.</p></blockquote><p class="wp-block-paragraph">Quando i processi sono davvero specifici, quindi, vale la pena valutare uno sviluppo su misura in ambiente cloud. In questo modo avrai uno strumento che segue le tue regole, accessibile ovunque e pensato per evolvere insieme al business. È in questo scenario che i nostri servizi di <a href="https://renor.it/servizi/sviluppo-e-cloud/">sviluppo e cloud</a> diventano un&#039;opzione da mettere sul tavolo, accanto alle soluzioni pronte, per scegliere con criterio.</p><h2 class="wp-block-heading">I limiti dei CRM standard per le piccole e medie imprese</h2><p class="wp-block-paragraph">I CRM pronti all&#039;uso nascono per accontentare il maggior numero possibile di aziende. Proprio per questo, spesso finiscono per non adattarsi davvero a nessuna. Per una PMI con processi già rodati, infatti, questa impostazione &quot;universale&quot; si traduce in frizioni quotidiane che rallentano il team invece di supportarlo.</p><p class="wp-block-paragraph">Il primo problema è l&#039;eccesso di funzioni. Molte piattaforme offrono decine di moduli pensati per grandi organizzazioni: automazioni marketing complesse, gerarchie commerciali articolate, cruscotti che nessuno consulta. Il risultato è un&#039;interfaccia affollata. Questo allunga i tempi di apprendimento e scoraggia l&#039;adozione da parte dei collaboratori.</p><p class="wp-block-paragraph">Il secondo nodo è la rigidità dei processi. Il software impone il suo flusso di lavoro e chiede all&#039;azienda di adeguarsi, quando dovrebbe essere il contrario. Se il vostro ciclo di vendita, la gestione dei preventivi o il passaggio di consegne tra reparti seguono una logica particolare, vi ritroverete a forzare i dati dentro campi e stati che non li rappresentano.</p><ul class="wp-block-list"><li>Costi di licenza ricorrenti che crescono con il numero di utenti e con le funzioni &quot;premium&quot;, indipendentemente da quanto le usate davvero</li><li>Integrazioni mancanti o limitate con gestionale, fatturazione, e-commerce o strumenti già in uso, che costringono a doppie digitazioni e dati non allineati</li><li>Personalizzazioni superficiali: potete cambiare qualche etichetta, ma non la logica di fondo che conta davvero</li><li>Dipendenza dal fornitore, che decide tempi, prezzi e futuro della piattaforma al posto vostro</li></ul><p class="wp-block-paragraph">Sommati, questi limiti hanno un costo concreto: tempo perso, dati poco affidabili e un investimento mensile che non si ferma mai. È qui che uno sviluppo CRM su misura per PMI inizia ad avere senso, perché parte dai vostri processi reali invece di imporne di estranei.</p><p class="wp-block-paragraph">Con un&#039;attività di sviluppo e cloud, il gestionale clienti può essere disegnato attorno al vostro modo di lavorare. Inoltre, può essere reso accessibile in modo affidabile ovunque serva, senza portarsi dietro il peso di funzioni che non userete mai.</p><h2 class="wp-block-heading">Sviluppo CRM su misura per PMI: quando conviene davvero</h2><p class="wp-block-paragraph">Il su misura non è sempre la scelta migliore: a volte una soluzione pronta copre bene le esigenze e permette di partire subito. La domanda giusta, quindi, non è &quot;quale CRM è il migliore&quot;, ma &quot;quanto i miei processi si discostano da uno standard&quot;. Più il modo di lavorare della tua azienda è specifico, più un CRM costruito sulle tue reali necessità ripaga l&#039;investimento. Ecco i criteri concreti da valutare.</p><ul class="wp-block-list"><li>Processi commerciali specifici: se il tuo ciclo di vendita segue passaggi, ruoli o regole che nessun software pronto rispecchia, adattare lo strumento standard genera compromessi continui. Un CRM su misura si modella sul tuo flusso, non il contrario.</li><li>Integrazione con gestionali ed ERP esistenti: quando dati anagrafici, ordini, fatturazione o magazzino vivono già in altri sistemi, la vera priorità è farli dialogare. Se le soluzioni pronte offrono solo connettori parziali, il su misura permette un&#039;integrazione pulita.</li><li>Volume e complessità dei dati: grandi quantità di informazioni o strutture dati particolari possono mettere in difficoltà i sistemi standard, sia per prestazioni sia per costi.</li><li>Esigenze di automazione: se vuoi automatizzare attività ricorrenti secondo logiche tue, e le automazioni preconfezionate non bastano, la personalizzazione diventa un vantaggio operativo misurabile.</li></ul><p class="wp-block-paragraph">Un modo pratico per decidere: elenca le operazioni che oggi fai a mano, fuori dal software, perché nessuno strumento le gestisce. Se questa lista è lunga, il su misura merita una valutazione seria. Se invece si tratta di poche eccezioni, allora una soluzione pronta ben configurata è probabilmente più efficiente.</p><blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow"><p>Il su misura conviene quando il costo dei compromessi quotidiani supera il costo di costruire lo strumento giusto.</p></blockquote><p class="wp-block-paragraph">Sul piano tecnologico, un progetto di questo tipo richiede competenze di sviluppo e un&#039;infrastruttura affidabile. Il nostro servizio di sviluppo e cloud nasce proprio per accompagnare le PMI in questo percorso, dalla progettazione all&#039;esercizio. Se vuoi capire più a fondo logiche, tempi e modalità di un progetto costruito ad hoc, trovi un approfondimento nel nostro articolo dedicato allo sviluppo software su misura.</p><h2 class="wp-block-heading">Automazione e integrazioni: il CRM al centro dei processi aziendali</h2><p class="wp-block-paragraph">Un CRM su misura dà il meglio quando smette di essere un semplice archivio di contatti. Diventa così il punto di raccordo tra le attività quotidiane dell&#039;azienda. La differenza non sta solo nel conservare i dati, ma nel farli circolare tra i reparti, riducendo il lavoro manuale che rallenta il commerciale, l&#039;amministrazione e il post-vendita.</p><p class="wp-block-paragraph">Il primo vantaggio concreto è l&#039;automazione delle attività ripetitive. Molte operazioni che oggi occupano ore di lavoro possono essere gestite dal sistema senza intervento umano, con meno errori e tempi di risposta più rapidi verso i clienti.</p><ul class="wp-block-list"><li>Follow-up commerciali programmati: promemoria e email automatiche a chi non risponde da giorni, così nessun lead resta senza risposta.</li><li>Reportistica automatica: cruscotti e report periodici generati e inviati ai responsabili senza dover estrarre dati a mano.</li><li>Flussi commerciali guidati: passaggi di stato dell&#039;opportunità, assegnazione dei lead al venditore giusto, notifiche interne quando una trattativa avanza.</li><li>Gestione delle scadenze: rinnovi, preventivi in attesa, solleciti di pagamento segnalati in automatico.</li></ul><p class="wp-block-paragraph">Il secondo vantaggio riguarda le integrazioni. Un CRM personalizzato può dialogare con gli strumenti che già usate ogni giorno: gestionale, fatturazione, posta elettronica, e-commerce o portali di supporto. In questo modo un&#039;informazione inserita una sola volta è disponibile ovunque serva, senza doppie digitazioni e senza dati disallineati.</p><blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow"><p>Un dato inserito una volta e utilizzabile da tutti i reparti: è questo il segnale che il CRM è diventato il centro dei processi, e non l&#039;ennesimo strumento da aggiornare a mano.</p></blockquote><p class="wp-block-paragraph">È proprio su questo terreno che uno sviluppo su misura mostra il suo valore rispetto a una soluzione preconfezionata: le automazioni e le integrazioni vengono costruite intorno al vostro modo di lavorare, non il contrario. Attraverso servizi di sviluppo e cloud è possibile realizzare queste connessioni in modo scalabile, mantenendo i dati accessibili da più sedi.</p><p class="wp-block-paragraph">Se volete approfondire come intervenire sulle attività manuali che assorbono più tempo, il tema si collega direttamente al nostro articolo sull&#039;automazione dei processi per le PMI. Lì analizziamo i flussi tipici da ottimizzare prima ancora di scegliere gli strumenti.</p><h2 class="wp-block-heading">Costi e tempi dello sviluppo CRM su misura per PMI</h2><p class="wp-block-paragraph">Chi valuta un CRM su misura si pone due domande legittime: quanto costa e quanto tempo richiede. Non esiste una risposta unica, perché il prezzo e la durata dipendono da scelte concrete. Capire quali sono queste variabili aiuta a impostare aspettative realistiche e a preparare una richiesta di preventivo mirata, evitando sorprese in corso d&#039;opera.</p><p class="wp-block-paragraph">Il primo fattore che incide sui costi è l&#039;analisi iniziale. Prima di scrivere una riga di codice serve mappare i flussi di lavoro, definire chi userà lo strumento e stabilire quali dati sono davvero utili. Una fase di analisi curata riduce gli errori successivi. Di fatto, quindi, contiene i costi complessivi: è un investimento, non una voce da comprimere.</p><p class="wp-block-paragraph">Il secondo elemento è l&#039;ampiezza delle funzionalità. Un CRM che gestisce solo anagrafiche e opportunità di vendita ha tempi e costi diversi da uno che include preventivi, reportistica avanzata o gestione post-vendita. Anche le integrazioni con i sistemi già in uso pesano sul preventivo: più fonti di dati vanno collegate, più aumenta il lavoro di sviluppo e di test.</p><ul class="wp-block-list"><li>Analisi e definizione dei processi: la base su cui si costruisce tutto il progetto.</li><li>Numero e complessità delle funzionalità richieste.</li><li>Integrazioni con gestionali, posta elettronica o altri strumenti aziendali.</li><li>Migrazione dei dati esistenti verso il nuovo sistema.</li><li>Formazione degli utenti e affiancamento nelle prime settimane.</li></ul><p class="wp-block-paragraph">Va poi considerata la manutenzione, spesso sottovalutata. Un software vive nel tempo: richiede aggiornamenti, correzioni e piccole evoluzioni man mano che l&#039;azienda cresce. Prevedere fin dall&#039;inizio un budget ricorrente per l&#039;assistenza evita che lo strumento diventi obsoleto. Anche la scelta di ospitare il sistema in cloud incide, perché sposta parte dei costi verso una spesa continuativa più prevedibile e scalabile.</p><p class="wp-block-paragraph">Il nostro servizio di sviluppo e cloud nasce proprio per accompagnare la PMI in queste fasi, dall&#039;analisi alla realizzazione fino alla gestione nel tempo. Il modo migliore per avere numeri concreti è partire da una descrizione precisa delle proprie esigenze: più chiaro è il punto di partenza, più il preventivo sarà affidabile.</p><h2 class="wp-block-heading">Come RENOR &amp; Partners affianca le PMI nello sviluppo CRM</h2><p class="wp-block-paragraph">Affrontare un progetto CRM su misura significa prendere decisioni tecniche e organizzative che, per un&#039;azienda non strutturata sul fronte IT, possono risultare complesse da gestire in autonomia. Il nostro ruolo è proprio questo: tradurre le esigenze concrete del vostro business in una soluzione funzionante, senza chiedervi di diventare esperti di tecnologia.</p><p class="wp-block-paragraph">Con il servizio Sviluppo e cloud accompagniamo le PMI lungo tutto il percorso, dalla comprensione dei processi esistenti fino alla messa in esercizio dello strumento. L&#039;obiettivo non è consegnarvi un software e sparire. Vogliamo invece costruire insieme una piattaforma che rispecchi il modo in cui lavorate davvero e che possa crescere con voi.</p><p class="wp-block-paragraph">Il nostro metodo di lavoro si articola in fasi chiare, pensate per darvi visibilità e controllo in ogni momento:</p><ul class="wp-block-list"><li>Analisi iniziale: partiamo dall&#039;ascolto dei vostri processi commerciali e operativi, per capire cosa serve realmente e dove un CRM può portare valore.</li><li>Progettazione condivisa: definiamo insieme funzionalità, priorità e tempistiche, così da concentrare l&#039;investimento su ciò che conta.</li><li>Sviluppo su misura: costruiamo la soluzione adattandola alle vostre esigenze, evitando funzioni superflue e complessità inutili.</li><li>Rilascio in cloud: mettiamo a disposizione un&#039;infrastruttura affidabile e accessibile, senza che dobbiate gestire server o sistemi internamente.</li><li>Supporto continuativo: restiamo al vostro fianco anche dopo l&#039;avvio, per adeguare lo strumento all&#039;evoluzione dell&#039;azienda.</li></ul><p class="wp-block-paragraph">Lavorare con un partner unico per sviluppo e cloud vi permette di avere un solo interlocutore responsabile del risultato. Questo riduce tempi di coordinamento e rischi di incomprensioni. Per un imprenditore che deve concentrarsi sul proprio business, infatti, questa continuità è spesso la differenza tra un progetto che si arena e uno che entra davvero a regime.</p><blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow"><p>Un buon CRM non nasce da un catalogo di funzioni, ma dalla comprensione di come lavora la vostra azienda.</p></blockquote><p class="wp-block-paragraph">Se state valutando lo sviluppo CRM su misura per PMI, il primo passo non richiede impegni: una consulenza iniziale ci consente di analizzare la vostra situazione e indicarvi la strada più sensata, anche in termini di costi e priorità. Contattate RENOR &amp; Partners per fissare un primo confronto e capire insieme se lo sviluppo su misura è la scelta giusta per la vostra realtà.</p>

<div class="wp-block-group scriba-cta"><div class="wp-block-group__inner-container is-layout-flow wp-block-group-is-layout-flow"><p><strong>Ti serve un supporto concreto?</strong> Scopri il nostro servizio <a href="https://renor.it/servizi/sviluppo-e-cloud/">Sviluppo e cloud</a> oppure <a href="https://renor.it/contatti/">contattaci</a> per una consulenza.</p></div></div>

<h2 class="wp-block-heading">Leggi anche</h2>

<ul class="wp-block-list"><li><a href="https://renor.it/blog/sviluppo-software-programmazione/sviluppo-software-su-misura-per-aziende/">Sviluppo software su misura per aziende: quando conviene e quanto costa</a></li><li><a href="https://renor.it/blog/intelligenza-artificiale-algoritmi/automazione-processi-con-ai-per-pmi-costo/">Automazione dei processi con l&#8217;AI per PMI: quanto costa davvero</a></li></ul><p>L'articolo <a href="https://renor.it/blog/sviluppo-software-programmazione/sviluppo-crm-su-misura-per-pmi/">Sviluppo CRM su misura per PMI: quando conviene e cosa valutare</a> proviene da <a href="https://renor.it">RENOR &amp; Partners S.r.l.</a>.</p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Software House per Gestionale Personalizzato in Italia: Guida alla Scelta</title>
		<link>https://renor.it/blog/sviluppo-software-programmazione/software-house-sviluppo-gestionale-personalizzato-italia/</link>
		
		<dc:creator><![CDATA[Simone Renzi]]></dc:creator>
		<pubDate>Tue, 01 Sep 2026 10:43:58 +0000</pubDate>
				<category><![CDATA[Sviluppo Software & Programmazione]]></category>
		<category><![CDATA[automazione]]></category>
		<category><![CDATA[innovazione]]></category>
		<category><![CDATA[renor]]></category>
		<category><![CDATA[trasformazione digitale]]></category>
		<guid isPermaLink="false">https://renor.it/blog/sviluppo-software-programmazione/software-house-sviluppo-gestionale-personalizzato-italia/</guid>

					<description><![CDATA[<p>Cerchi una software house sviluppo gestionale personalizzato Italia? Scopri in questa guida criteri di scelta, fasi del progetto, costi e vantaggi concreti.</p>
<p>L'articolo <a href="https://renor.it/blog/sviluppo-software-programmazione/software-house-sviluppo-gestionale-personalizzato-italia/">Software House per Gestionale Personalizzato in Italia: Guida alla Scelta</a> proviene da <a href="https://renor.it">RENOR &amp; Partners S.r.l.</a>.</p>
]]></description>
										<content:encoded><![CDATA[<h2 class="wp-block-heading">Software house sviluppo gestionale personalizzato Italia: quando conviene davvero</h2><p class="wp-block-paragraph">Una software house sviluppo gestionale personalizzato Italia diventa la scelta giusta quando un software pronto all&#039;uso non basta più. Infatti, un gestionale standard costa poco all&#039;inizio, si attiva in fretta e copre le esigenze più comuni come fatturazione, magazzino e contabilità. Per molte aziende, dunque, è più che sufficiente. Il problema nasce però quando i tuoi processi non rientrano negli schemi previsti dal software: a quel punto sei tu a doverti adattare allo strumento, e non il contrario.</p><p class="wp-block-paragraph">Il primo segnale d&#039;allarme è proprio questo. Se il tuo team perde tempo con passaggi manuali o fogli di calcolo paralleli, lo strumento non segue davvero il tuo modo di lavorare. Inoltre, se servono &quot;trucchi&quot; per far funzionare il gestionale come vuoi tu, significa che qualcosa non va. Sono infatti ore di lavoro nascoste che, sommate nell&#039;arco di un anno, pesano molto più di quanto sembri.</p><p class="wp-block-paragraph">Il secondo segnale riguarda le integrazioni. Un gestionale che non dialoga con il tuo e-commerce, con il CRM o con i sistemi dei fornitori genera doppie registrazioni, errori e dati non allineati. Se ti ritrovi a copiare informazioni da un programma all&#039;altro, il costo non è solo il tempo perso. Infatti, c&#039;è anche il rischio di decisioni prese su numeri sbagliati.</p><p class="wp-block-paragraph">Il terzo segnale è economico. I gestionali standard hanno licenze che crescono con il numero di utenti, i moduli aggiuntivi e le funzioni &quot;premium&quot;. Vale la pena quindi fare un conto onesto:</p><ul class="wp-block-list"><li>Quanto pagherai di licenze e canoni nei prossimi tre o cinque anni?</li><li>Quante funzioni paghi ma non usi, e quante ti mancano?</li><li>Quanto ti costano davvero le attività manuali che il software non automatizza?</li></ul><p class="wp-block-paragraph">Quando le risposte iniziano a preoccuparti, il software su misura smette di essere un lusso. Diventa invece un investimento razionale. Un gestionale personalizzato modella infatti le funzioni esatte sui tuoi processi. Inoltre, integra gli strumenti che già usi ed elimina i costi di licenza per funzioni superflue. Con lo sviluppo su misura e l&#039;infrastruttura cloud, la soluzione cresce insieme all&#039;azienda, restando accessibile ovunque e adattabile nel tempo.</p><blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow"><p>La domanda giusta non è &quot;quanto costa il software su misura&quot;, ma &quot;quanto mi sta già costando continuare ad adattarmi a uno standard che non fa al caso mio&quot;.</p></blockquote><h2 class="wp-block-heading">Cosa fa una software house per sviluppo gestionale personalizzato</h2><p class="wp-block-paragraph">Affidarsi a una software house per lo sviluppo di un gestionale personalizzato significa attivare un percorso strutturato, non semplicemente &quot;far scrivere del codice&quot;. Il valore di un partner solido sta proprio nel metodo. Infatti, ogni fase è pensata per ridurre i rischi e garantire che il gestionale rispecchi davvero il funzionamento della tua azienda. Ecco quindi le attività principali che entrano in gioco.</p><ul class="wp-block-list"><li>Analisi dei processi: prima di scrivere una riga di codice, si studiano il flusso di lavoro, i punti critici e gli obiettivi concreti. È qui che emergono le vere esigenze, spesso diverse da quelle percepite all&#039;inizio.</li><li>Progettazione: si definiscono l&#039;architettura, le funzionalità prioritarie e l&#039;esperienza d&#039;uso, così da avere una mappa chiara prima dello sviluppo e stime realistiche di tempi e costi.</li><li>Sviluppo: il software viene costruito per fasi, con rilasci intermedi che permettono di testare e correggere la rotta senza attendere la fine del progetto.</li><li>Integrazione con i sistemi esistenti: il gestionale dialoga con gli strumenti già in uso, come contabilità, e-commerce e magazzino, evitando doppie immissioni e dati sparsi.</li><li>Manutenzione ed evoluzione: dopo il rilascio il lavoro continua con aggiornamenti, correzioni e nuove funzionalità che seguono la crescita dell&#039;azienda.</li></ul><p class="wp-block-paragraph">È qui che la differenza tra una software house strutturata e un freelance improvvisato diventa evidente. Un professionista singolo può realizzare progetti anche validi. Tuttavia, difficilmente garantisce continuità: se si rende irreperibile, il gestionale rischia di restare bloccato senza chi lo conosca. Un team, invece, distribuisce le competenze e assicura assistenza nel tempo, documentazione e capacità di intervenire su più fronti.</p><p class="wp-block-paragraph">Un altro elemento decisivo è la componente di <a href="https://renor.it/servizi/sviluppo-e-cloud/">sviluppo e cloud</a>. Costruire il gestionale con un&#039;infrastruttura affidabile permette infatti di accedervi da più sedi e dispositivi, con dati sempre disponibili e aggiornati. Questo si traduce in maggiore continuità operativa e in un software che cresce insieme all&#039;azienda, senza vincoli legati a una singola postazione.</p><blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow"><p>Un buon gestionale su misura non nasce dal codice, ma dalla comprensione profonda di come lavora davvero la tua azienda.</p></blockquote><h2 class="wp-block-heading">Come scegliere la software house giusta per il gestionale in Italia</h2><p class="wp-block-paragraph">Scegliere il partner giusto per una software house sviluppo gestionale personalizzato Italia è una decisione che influenza l&#039;operatività aziendale per anni. Non si tratta solo di confrontare preventivi, ma di valutare affidabilità, competenze e trasparenza. Ecco quindi una checklist concreta per orientare la decisione e fare le domande giuste fin dal primo incontro.</p><h2 class="wp-block-heading">I criteri di valutazione essenziali</h2><ul class="wp-block-list"><li>Competenze cloud: verificate se la software house sviluppa soluzioni pensate per il cloud, che garantiscono accessibilità da più sedi, scalabilità e minore dipendenza da server fisici da manutenere internamente.</li><li>Referenze e casi concreti: chiedete esempi di progetti realizzati in settori simili al vostro. Un partner solido non ha problemi a mostrare risultati e a mettervi in contatto con clienti esistenti.</li><li>Metodologia di lavoro: capite come organizzano il progetto. Rilasci graduali e revisioni frequenti permettono di correggere la rotta prima che sia troppo tardi.</li><li>Assistenza post-rilascio: il software non finisce con la consegna. Informatevi su tempi di risposta, modalità di supporto e gestione degli aggiornamenti nel tempo.</li><li>Proprietà del codice: chiarite fin da subito chi possiede il codice sorgente. È un aspetto cruciale per non restare vincolati a un unico fornitore in futuro.</li></ul><h2 class="wp-block-heading">Le domande da porre al primo colloquio</h2><ul class="wp-block-list"><li>Come gestite le fasi del progetto e con quale frequenza mi aggiornate sullo stato di avanzamento?</li><li>Il software sarà ospitato in cloud e come garantite la disponibilità del servizio?</li><li>Cosa succede se in futuro volessi cambiare fornitore o gestire internamente il codice?</li><li>Quali garanzie offrite sull&#039;assistenza dopo il rilascio e con quali costi?</li><li>Potete mostrarmi progetti simili al mio già in produzione?</li></ul><p class="wp-block-paragraph">Un partner che risponde con chiarezza a queste domande dimostra trasparenza e maturità. In quest&#039;ottica, un approccio orientato allo sviluppo e al cloud rappresenta un buon punto di partenza. Consente infatti di realizzare un gestionale su misura accessibile e pensato per crescere insieme alla vostra azienda.</p><blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow"><p>La software house giusta non è quella che promette di più, ma quella che spiega meglio come lavora e cosa resta nelle vostre mani a progetto concluso.</p></blockquote><h2 class="wp-block-heading">Le fasi di un progetto gestionale personalizzato: dall&#039;analisi al rilascio</h2><figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="800" height="800" src="https://renor.it/wp-content/uploads/2026/09/software-house-per-gestionale-personalizzato-in-italia-guida-alla-scelta-fig-1-800x800.png" alt="Team di una software house al lavoro su un gestionale personalizzato" class="wp-image-3131" srcset="https://renor.it/wp-content/uploads/2026/09/software-house-per-gestionale-personalizzato-in-italia-guida-alla-scelta-fig-1-800x800.png 800w, https://renor.it/wp-content/uploads/2026/09/software-house-per-gestionale-personalizzato-in-italia-guida-alla-scelta-fig-1-150x150.png 150w, https://renor.it/wp-content/uploads/2026/09/software-house-per-gestionale-personalizzato-in-italia-guida-alla-scelta-fig-1-300x300.png 300w" sizes="auto, (max-width: 800px) 100vw, 800px" /></figure><p class="wp-block-paragraph">Un progetto gestionale su misura non nasce dalla scrittura del codice, ma dalla comprensione del vostro modo di lavorare. Conoscere le fasi tipiche del percorso vi aiuta a capire cosa aspettarvi. Vi aiuta anche a fissare tempi realistici e a mantenere il controllo sull&#039;investimento in ogni momento.</p><ul class="wp-block-list"><li>Analisi e raccolta requisiti: si mappano processi, ruoli e flussi di dati aziendali. È la fase in cui si traduce ciò che fate ogni giorno in specifiche chiare, individuando priorità e vincoli.</li><li>Prototipo: prima di sviluppare, si costruisce un modello navigabile delle schermate principali. Vi permette di &#039;vedere&#039; il gestionale e correggere la rotta quando le modifiche costano poco.</li><li>Sviluppo iterativo: il software viene realizzato per moduli, rilasciati e verificati a piccoli passi. Ad ogni ciclo potete valutare risultati concreti, senza attendere mesi per un unico grande consegnamento.</li><li>Test: si controllano funzionamento, sicurezza e casi limite, coinvolgendo anche chi userà lo strumento sul campo per far emergere errori e imprecisioni prima del rilascio.</li><li>Formazione: le persone vengono guidate nell&#039;uso quotidiano, con materiale di supporto. Un gestionale efficace è quello che il team adotta senza attriti.</li><li>Go-live: l&#039;avvio in produzione avviene in modo controllato, spesso con un periodo di affiancamento per gestire i primi giorni operativi e intervenire rapidamente.</li></ul><p class="wp-block-paragraph">Questo metodo riduce il rischio proprio perché distribuisce le verifiche lungo tutto il percorso, anziché concentrarle alla fine. Le decisioni si prendono infatti su elementi tangibili. Inoltre, le eventuali correzioni si affrontano quando sono ancora semplici ed economiche da gestire.</p><p class="wp-block-paragraph">Un aspetto spesso sottovalutato riguarda l&#039;infrastruttura su cui il gestionale vive. Con un servizio di sviluppo e cloud, l&#039;applicazione viene rilasciata in un ambiente accessibile e mantenibile. Così potete concentrarvi sull&#039;uso quotidiano senza doverne gestire in prima persona la complessità tecnica.</p><blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow"><p>Un progetto ben condotto non è quello senza imprevisti, ma quello in cui gli imprevisti emergono presto e si risolvono con metodo.</p></blockquote><p class="wp-block-paragraph">Chiedete sempre alla software house come struttura queste fasi e quali momenti di verifica prevede: la risposta vi dirà molto sulla trasparenza e sulla professionalità con cui lavora.</p><h2 class="wp-block-heading">Cloud, integrazioni e sicurezza: cosa considerare oltre alle funzionalità</h2><p class="wp-block-paragraph">Quando si valuta un gestionale su misura, l&#039;attenzione si concentra quasi sempre sulle funzionalità: cosa fa il software, quali processi automatizza, quali report produce. Sono aspetti importanti, ma non gli unici. Ci sono infatti tre elementi che spesso restano in secondo piano: la scalabilità del cloud, la capacità di integrarsi con i sistemi che già usate e la protezione dei dati. Nel tempo, questi determinano se il vostro investimento continuerà a dare valore o diventerà un peso.</p><h2 class="wp-block-heading">Scalabilità: crescere senza rifare tutto da capo</h2><p class="wp-block-paragraph">Un&#039;infrastruttura cloud ben progettata permette al gestionale di adattarsi al ritmo dell&#039;azienda. Se raddoppiano gli utenti, gli ordini o le sedi collegate, il sistema deve reggere senza rallentamenti. Inoltre, non deve costringervi a costose migrazioni. Chiedete sempre come viene gestito l&#039;aumento del carico e quali costi comporta la crescita: una risposta chiara oggi vi evita sorprese domani.</p><h2 class="wp-block-heading">Integrazioni: il gestionale non vive da solo</h2><p class="wp-block-paragraph">Difficilmente il nuovo software sostituirà tutto ciò che avete. Più spesso dovrà dialogare con l&#039;ERP contabile, il CRM commerciale, l&#039;e-commerce o gli strumenti di fatturazione. Un gestionale che scambia dati in automatico con questi sistemi elimina i doppi inserimenti e riduce gli errori. Verificate quindi se la software house progetta per l&#039;integrazione fin dall&#039;inizio, e non come una toppa applicata alla fine.</p><ul class="wp-block-list"><li>Con quali sistemi esistenti dovrà comunicare il gestionale?</li><li>I dati vengono sincronizzati in tempo reale o a intervalli?</li><li>Cosa succede se in futuro cambierete uno dei sistemi collegati?</li></ul><h2 class="wp-block-heading">Sicurezza: un requisito, non un extra</h2><figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="800" height="800" src="https://renor.it/wp-content/uploads/2026/09/software-house-per-gestionale-personalizzato-in-italia-guida-alla-scelta-fig-2-800x800.png" alt="Consulenza per lo sviluppo di un software gestionale su misura" class="wp-image-3132" srcset="https://renor.it/wp-content/uploads/2026/09/software-house-per-gestionale-personalizzato-in-italia-guida-alla-scelta-fig-2-800x800.png 800w, https://renor.it/wp-content/uploads/2026/09/software-house-per-gestionale-personalizzato-in-italia-guida-alla-scelta-fig-2-150x150.png 150w, https://renor.it/wp-content/uploads/2026/09/software-house-per-gestionale-personalizzato-in-italia-guida-alla-scelta-fig-2-300x300.png 300w" sizes="auto, (max-width: 800px) 100vw, 800px" /></figure><p class="wp-block-paragraph">I dati aziendali sono un patrimonio: anagrafiche clienti, listini, contratti. Perciò, la loro protezione deve essere prevista già in fase di progettazione, con backup regolari, controlli sugli accessi e conformità alle normative sulla privacy. Non è un dettaglio tecnico da delegare, ma una scelta di responsabilità verso i vostri clienti e la vostra attività.</p><p class="wp-block-paragraph">È proprio su questo terreno che si misura la solidità di un partner. Con il servizio di Sviluppo e cloud, in RENOR affrontiamo insieme questi tre aspetti fin dalle prime fasi del progetto. Così il gestionale nasce già pronto a crescere, a integrarsi e a proteggere i vostri dati.</p><h2 class="wp-block-heading">Costi, tempi e ritorno dell&#039;investimento di un gestionale personalizzato</h2><p class="wp-block-paragraph">Una delle domande più frequenti prima di avviare un progetto è: quanto costa e quanto tempo richiede? La risposta onesta è che dipende dalla complessità reale dei processi da digitalizzare. Un gestionale su misura non ha un listino fisso perché non è un prodotto da scaffale. È invece una soluzione costruita attorno al vostro modo di lavorare. Capire cosa muove il budget vi permette quindi di pianificare senza sorprese.</p><p class="wp-block-paragraph">I fattori che incidono maggiormente su costi e tempi sono pochi ma decisivi:</p><ul class="wp-block-list"><li>Il numero e la complessità dei processi da coprire (magazzino, ordini, produzione, fatturazione).</li><li>Le integrazioni con sistemi già in uso, come e-commerce, contabilità o strumenti di terze parti.</li><li>Il numero di utenti e i diversi ruoli e permessi da gestire.</li><li>I requisiti di sicurezza e di infrastruttura, soprattutto in caso di soluzioni in cloud.</li><li>La quantità e la qualità dei dati da migrare dai sistemi esistenti.</li></ul><p class="wp-block-paragraph">Sul fronte tempi, un primo modulo utilizzabile può richiedere poche settimane. Un sistema completo, invece, si sviluppa nell&#039;arco di alcuni mesi. Un approccio a rilasci progressivi, che introduce prima le funzioni più critiche, riduce il rischio. Inoltre, permette di iniziare a raccogliere valore prima che il progetto sia concluso.</p><p class="wp-block-paragraph">Il ritorno dell&#039;investimento non va misurato solo sul costo iniziale, ma sui benefici concreti nel tempo. Ecco quindi gli indicatori più significativi da monitorare:</p><ul class="wp-block-list"><li>Tempo risparmiato dalle persone su attività ripetitive ora automatizzate.</li><li>Riduzione degli errori manuali, con meno rilavorazioni e reclami.</li><li>Maggiore velocità nell&#039;accesso a dati aggiornati per decidere meglio.</li><li>Minori costi di licenze e strumenti scollegati sostituiti da un unico sistema.</li></ul><blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow"><p>Un gestionale su misura si ripaga quando il tempo che restituisce ogni mese supera stabilmente quanto è costato mantenerlo.</p></blockquote><p class="wp-block-paragraph">Per proteggere l&#039;investimento nel tempo, contano anche le scelte tecniche di sviluppo e cloud. Una base solida e un&#039;infrastruttura affidabile evitano infatti costi nascosti futuri. Rendono inoltre il sistema pronto a crescere con l&#039;azienda. Prima di partire, definite quindi insieme al partner quali metriche misurerete: è il modo più chiaro per giustificare la spesa e per verificare, dati alla mano, che l&#039;investimento stia producendo i risultati attesi.</p><h2 class="wp-block-heading">Il prossimo passo: parla con una software house per sviluppo gestionale personalizzato in Italia</h2><p class="wp-block-paragraph">Dopo aver valutato criteri, fasi, costi e aspetti tecnici, arriva il momento della decisione concreta. Il modo più efficace per capire se un gestionale su misura è la scelta giusta per la tua azienda non è continuare a raccogliere informazioni in astratto. È invece confrontarsi con chi progetta questi sistemi ogni giorno, partendo dai tuoi processi reali e dai tuoi obiettivi.</p><p class="wp-block-paragraph">RENOR &amp; Partners è una software house sviluppo gestionale personalizzato Italia, che affianca imprese e organizzazioni nella progettazione di soluzioni su misura e nella loro gestione in cloud.</p><p class="wp-block-paragraph">Lavorare con un partner sul territorio significa infatti parlare la stessa lingua. Significa anche comprendere il contesto normativo e operativo in cui ti muovi. Inoltre, significa avere un interlocutore raggiungibile quando serve, non solo in fase di vendita ma lungo tutto il ciclo di vita del progetto.</p><p class="wp-block-paragraph">Un primo confronto serve a mettere a fuoco alcune cose pratiche, prima ancora di parlare di sviluppo:</p><ul class="wp-block-list"><li>Quali processi aziendali rallentano davvero il tuo lavoro e meritano di essere digitalizzati per primi</li><li>Se conviene un percorso su misura o se una soluzione più standard può bastare, almeno inizialmente</li><li>Come impostare il progetto per ottenere risultati concreti in tempi ragionevoli, senza sprechi</li><li>Quali priorità tecniche e organizzative affrontare per non trovarti bloccato tra sei mesi</li></ul><p class="wp-block-paragraph">In questo passaggio la <a href="https://renor.it/servizi/consulenza-it/">consulenza IT</a> e la consulenza strategica giocano un ruolo decisivo. Aiutano infatti a tradurre gli obiettivi di business in scelte tecnologiche sostenibili, definendo cosa costruire, in che ordine e con quale ritorno atteso. È il modo migliore per evitare investimenti mal indirizzati e per costruire un sistema che cresca insieme all&#039;azienda.</p><blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow"><p>Un buon gestionale non nasce da un preventivo, ma da una conversazione onesta sui tuoi obiettivi.</p></blockquote><p class="wp-block-paragraph">Se stai valutando un gestionale personalizzato o vuoi semplicemente capire da dove iniziare, il consiglio è di prenotare una consulenza conoscitiva. Bastano infatti un incontro e una descrizione delle tue esigenze per ricevere una valutazione concreta, senza impegno, e per trasformare le riflessioni di questa guida in un percorso chiaro e su misura per la tua realtà.</p>

<div class="wp-block-group scriba-cta"><div class="wp-block-group__inner-container is-layout-flow wp-block-group-is-layout-flow"><p><strong>Ti serve un supporto concreto?</strong> Scopri il nostro servizio <a href="https://renor.it/servizi/sviluppo-e-cloud/">Sviluppo e cloud</a> oppure <a href="https://renor.it/contatti/">contattaci</a> per una consulenza.</p></div></div>

<h2 class="wp-block-heading">Leggi anche</h2>

<ul class="wp-block-list"><li><a href="https://renor.it/servizi/consulenza-strategica/">Consulenza strategica</a></li></ul><p>L'articolo <a href="https://renor.it/blog/sviluppo-software-programmazione/software-house-sviluppo-gestionale-personalizzato-italia/">Software House per Gestionale Personalizzato in Italia: Guida alla Scelta</a> proviene da <a href="https://renor.it">RENOR &amp; Partners S.r.l.</a>.</p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Sviluppo software su misura per aziende: quando conviene e quanto costa</title>
		<link>https://renor.it/blog/sviluppo-software-programmazione/sviluppo-software-su-misura-per-aziende/</link>
		
		<dc:creator><![CDATA[Simone Renzi]]></dc:creator>
		<pubDate>Mon, 31 Aug 2026 10:35:41 +0000</pubDate>
				<category><![CDATA[Sviluppo Software & Programmazione]]></category>
		<category><![CDATA[automazione]]></category>
		<category><![CDATA[innovazione]]></category>
		<category><![CDATA[renor]]></category>
		<category><![CDATA[trasformazione digitale]]></category>
		<guid isPermaLink="false">https://renor.it/blog/sviluppo-software-programmazione/sviluppo-software-su-misura-per-aziende/</guid>

					<description><![CDATA[<p>Scopri quando conviene lo sviluppo software su misura per aziende: vantaggi, fasi del progetto, costi e come scegliere il partner giusto per la tua impresa.</p>
<p>L'articolo <a href="https://renor.it/blog/sviluppo-software-programmazione/sviluppo-software-su-misura-per-aziende/">Sviluppo software su misura per aziende: quando conviene e quanto costa</a> proviene da <a href="https://renor.it">RENOR &amp; Partners S.r.l.</a>.</p>
]]></description>
										<content:encoded><![CDATA[<h2 class="wp-block-heading">Sviluppo software su misura per aziende: quando conviene rispetto a una soluzione pronta</h2><p class="wp-block-paragraph">Lo sviluppo software su misura per aziende è un&#039;applicazione progettata e costruita specificamente sui tuoi processi. Una soluzione pronta, invece, è un prodotto già confezionato. Infatti è pensato per adattarsi a molte imprese diverse: la usi così com&#039;è, con al massimo qualche opzione di configurazione. Quindi non esiste una scelta migliore in assoluto: dipende da quanto le tue esigenze sono comuni o specifiche.</p><p class="wp-block-paragraph">La domanda giusta da porsi non è &quot;quale software è più completo&quot;. Piuttosto, chiediti se il tuo modo di lavorare è simile a quello di altre aziende. Oppure se ha caratteristiche che ti distinguono. Se gestisci fatturazione, magazzino o contabilità in modo abbastanza standard, un gestionale pronto copre bene il fabbisogno. Inoltre costa meno ed è disponibile da subito. Se invece i tuoi processi sono il tuo vantaggio competitivo, forzarli dentro uno strumento rigido rischia di rallentarti.</p><p class="wp-block-paragraph">Ci sono alcuni segnali concreti che indicano quando conviene valutare una soluzione custom.</p><ul class="wp-block-list"><li>Usi molti fogli di calcolo e passaggi manuali per colmare i limiti dei software attuali.</li><li>I programmi che hai non &quot;dialogano&quot; tra loro e devi reinserire gli stessi dati più volte.</li><li>Un processo chiave della tua attività non è coperto da alcun prodotto standard.</li><li>Paghi licenze per funzioni che non usi, ma ti manca proprio ciò che ti servirebbe.</li><li>Prevedi di crescere e temi che lo strumento attuale non regga volumi o nuove esigenze.</li></ul><p class="wp-block-paragraph">Se ti riconosci in più di questi punti, allora una soluzione su misura potrebbe farti risparmiare tempo. Inoltre può ridurre gli errori. In molti casi, infatti, la strada più sensata è ibrida: mantenere gli strumenti standard dove funzionano e sviluppare su misura solo le parti davvero distintive, integrandole tra loro.</p><blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow"><p>Il software giusto non è quello con più funzioni, ma quello che si adatta al tuo modo di lavorare invece di costringerti a cambiarlo.</p></blockquote><p class="wp-block-paragraph">È qui che entra in gioco il nostro servizio di <a href="https://renor.it/servizi/sviluppo-e-cloud/">sviluppo e cloud</a>: costruiamo l&#039;applicazione attorno ai tuoi processi e la rendiamo accessibile in modo affidabile. Così puoi partire con ciò che serve oggi e far crescere la soluzione insieme all&#039;azienda.</p><h2 class="wp-block-heading">I vantaggi dello sviluppo software su misura per aziende: processi, competitività e scalabilità</h2><p class="wp-block-paragraph">Un software costruito attorno al modo in cui lavora la tua azienda produce risultati misurabili fin dai primi mesi. Il motivo è semplice: invece di adattare le persone a uno strumento pensato per altri, lo strumento si adatta ai processi che già generano valore. Vediamo quindi dove si concentrano i benefici più tangibili.</p><h2 class="wp-block-heading">Processi più fluidi e meno errori manuali</h2><p class="wp-block-paragraph">Molte inefficienze non nascono da mancanza di impegno, ma da attività ripetitive svolte a mano. Pensiamo ai dati ricopiati da un file all&#039;altro, ai controlli fatti a memoria, ai passaggi tra reparti gestiti via email. Ogni passaggio manuale, infatti, è un punto in cui possono nascere errori e ritardi. Un software su misura automatizza proprio questi snodi. Inoltre riduce le rilavorazioni e libera tempo delle persone per attività a maggior valore.</p><ul class="wp-block-list"><li>Meno tempo perso in inserimenti e verifiche manuali</li><li>Riduzione degli errori che generano costi nascosti e reclami</li><li>Informazioni aggiornate e condivise tra i reparti, senza duplicazioni</li></ul><h2 class="wp-block-heading">Un vantaggio competitivo che i concorrenti non copiano</h2><p class="wp-block-paragraph">Quando il software rispecchia il tuo modo specifico di servire i clienti, quel vantaggio diventa difficile da replicare. Tempi di risposta più rapidi, offerte più precise, tracciabilità completa: sono elementi che il cliente percepisce. Infatti ti distinguono dalla concorrenza. A differenza di una soluzione pronta, disponibile a chiunque, uno strumento su misura incorpora il tuo know-how e lavora a tuo favore.</p><h2 class="wp-block-heading">Crescita e scalabilità nel tempo</h2><p class="wp-block-paragraph">Un buon investimento non risolve solo il problema di oggi: accompagna l&#039;azienda mentre cresce. Pensiamo all&#039;aumento dei volumi, alle nuove sedi, ai nuovi servizi da gestire senza dover cambiare tutto ogni volta. Qui entra in gioco la nostra proposta di sviluppo e cloud: costruiamo l&#039;applicazione secondo le tue esigenze. Poi la portiamo su un&#039;infrastruttura cloud che può adeguare le risorse alla crescita reale. In questo modo eviti costi fissi sproporzionati nelle fasi iniziali.</p><blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow"><p>Il valore di un software su misura non si misura solo in ciò che fa oggi, ma in quanto ti permette di crescere domani senza ripartire da zero.</p></blockquote><h2 class="wp-block-heading">Le fasi di un progetto di sviluppo software su misura per aziende: dall&#039;analisi al rilascio</h2><figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="800" height="800" src="https://renor.it/wp-content/uploads/2026/08/sviluppo-software-su-misura-per-aziende-quando-conviene-e-quanto-costa-fig-1-800x800.png" alt="Team di sviluppo software al lavoro su un progetto aziendale su misura" class="wp-image-3127" srcset="https://renor.it/wp-content/uploads/2026/08/sviluppo-software-su-misura-per-aziende-quando-conviene-e-quanto-costa-fig-1-800x800.png 800w, https://renor.it/wp-content/uploads/2026/08/sviluppo-software-su-misura-per-aziende-quando-conviene-e-quanto-costa-fig-1-150x150.png 150w, https://renor.it/wp-content/uploads/2026/08/sviluppo-software-su-misura-per-aziende-quando-conviene-e-quanto-costa-fig-1-300x300.png 300w" sizes="auto, (max-width: 800px) 100vw, 800px" /></figure><p class="wp-block-paragraph">Un progetto di sviluppo su misura non è un&#039;improvvisazione: segue un percorso strutturato in fasi ben definite. Conoscerle in anticipo, infatti, ti permette di sapere cosa aspettarti. Saprai anche in quali momenti sarà richiesto il tuo coinvolgimento. Inoltre potrai tenere sotto controllo tempi e budget. Ecco le tappe principali.</p><ul class="wp-block-list"><li>Analisi dei requisiti: si parte dai tuoi obiettivi di business e dai processi reali dell&#039;azienda. In questa fase si raccolgono le esigenze delle persone che useranno il software e si trasformano in requisiti chiari. È il momento più importante: qui si evitano fraintendimenti che costerebbero cari in seguito.</li><li>Progettazione: si definisce come sarà costruita la soluzione, dall&#039;architettura tecnica all&#039;esperienza d&#039;uso. Spesso vengono realizzate prime bozze o prototipi delle schermate. Così puoi vedere e correggere prima ancora che venga scritta una riga di codice definitivo.</li><li>Sviluppo: è la fase in cui il software prende forma, di solito procedendo per parti successive. Lavorare per rilasci progressivi ti consente di vedere risultati concreti già durante il percorso, invece di attendere il prodotto finito senza riscontri intermedi.</li><li>Test e collaudo: ogni funzionalità viene verificata per assicurarsi che risponda ai requisiti e che sia affidabile. Il collaudo coinvolge anche te e il tuo team, che provate il software in condizioni vicine a quelle reali prima della messa in produzione.</li><li>Rilascio e manutenzione: il software viene messo in esercizio e reso disponibile agli utenti. Da qui inizia una fase continuativa di aggiornamenti, correzioni e miglioramenti. Infatti un gestionale su misura evolve insieme all&#039;azienda.</li></ul><p class="wp-block-paragraph">Un aspetto spesso sottovalutato è dove il software viene ospitato ed eseguito. Le nostre attività di sviluppo e cloud, infatti, consentono di gestire l&#039;intero ciclo: dalla realizzazione dell&#039;applicazione fino al suo funzionamento in ambiente cloud. Così non lasci scoperto il passaggio delicato tra la costruzione del software e il suo utilizzo quotidiano.</p><blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow"><p>Il valore di un progetto su misura non si misura solo nel giorno del rilascio, ma nella capacità di accompagnare l&#039;azienda nel tempo, fase dopo fase.</p></blockquote><h2 class="wp-block-heading">Integrazione con i sistemi che già usi: gestionali, ERP e strumenti esterni</h2><p class="wp-block-paragraph">Un software su misura raramente nasce in un contesto vuoto. Nella maggior parte delle aziende, infatti, esiste già un ecosistema di strumenti. Ad esempio il gestionale che governa ordini e magazzino, l&#039;ERP che tiene insieme contabilità e produzione, il CRM per i clienti, la piattaforma di e-commerce, il portale del corriere. Il valore di una nuova soluzione dipende quindi in buona parte dalla sua capacità di dialogare con questi sistemi, evitando isole di dati e doppie digitazioni.</p><p class="wp-block-paragraph">Il principio è semplice: un dato dovrebbe essere inserito una sola volta e poi circolare automaticamente dove serve. Quando l&#039;integrazione funziona, un ordine ricevuto online aggiorna il magazzino, genera il documento contabile e avvisa la logistica senza alcun intervento manuale. Quando invece i sistemi restano separati, il personale passa ore a ricopiare informazioni. Di conseguenza cresce il rischio concreto di errori e ritardi.</p><p class="wp-block-paragraph">Dal punto di vista tecnico, l&#039;integrazione si realizza soprattutto attraverso le API, cioè i canali con cui due programmi si scambiano dati in modo strutturato. La fattibilità e la complessità dipendono da quanto il software esistente è &quot;aperto&quot;. Infatti, alcuni gestionali moderni offrono connessioni pronte, altri più datati richiedono soluzioni intermedie. Per questo è un aspetto da valutare presto, già in fase di analisi, perché incide in modo sensibile su tempi e budget.</p><blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow"><p>Prima di sviluppare qualcosa di nuovo, chiediti sempre: con quali sistemi dovrà parlare, e questi sistemi sono in grado di farlo?</p></blockquote><p class="wp-block-paragraph">Su questo terreno un partner con competenze di sviluppo e cloud fa la differenza. Progettare l&#039;infrastruttura in cloud, infatti, consente di collegare più applicazioni in modo affidabile. Inoltre permette di far scalare i flussi quando i volumi crescono e di garantire che lo scambio di dati sia continuo e sicuro. È l&#039;approccio che seguiamo per costruire soluzioni che si inseriscono nel vostro ecosistema esistente, anziché sostituirlo per intero.</p><p class="wp-block-paragraph">Vale la pena considerare due punti prima di procedere:</p><ul class="wp-block-list"><li>I costi di integrazione meritano un capitolo a parte: ne parliamo più avanti, perché possono pesare quanto lo sviluppo stesso.</li><li>Una volta collegati i sistemi, si apre la strada all&#039;automazione dei processi e all&#039;uso dell&#039;intelligenza artificiale, evoluzioni naturali quando i dati sono già ordinati e disponibili in un unico flusso.</li></ul><h2 class="wp-block-heading">Quanto costa lo sviluppo software su misura per aziende: cosa incide sul preventivo</h2><p class="wp-block-paragraph">Chiedere quanto costa un software su misura è come chiedere quanto costa una casa: dipende dalle dimensioni, dai materiali e da cosa deve contenere. Per questo è difficile trovare un listino affidabile online. Diffida quindi di chi promette una cifra prima di aver capito il problema da risolvere. Ci sono però alcuni fattori concreti che spostano il preventivo. Conoscerli ti aiuta a valutare le proposte con occhio critico.</p><ul class="wp-block-list"><li>Complessità funzionale: quante cose deve fare il software e quanto sono articolati i flussi di lavoro. Un gestionale che automatizza pochi passaggi costa molto meno di una piattaforma che coordina più reparti, ruoli e regole di business.</li><li>Integrazioni: collegarsi a gestionali, ERP, e-commerce o strumenti esterni richiede tempo di analisi e sviluppo. Più sistemi devono &quot;parlarsi&quot;, maggiore è l&#039;impegno, soprattutto quando i software di partenza sono datati o poco documentati.</li><li>Numero di utenti e carico di lavoro: un applicativo usato da cinque persone ha esigenze diverse da uno che deve reggere migliaia di accessi simultanei senza rallentare.</li><li>Design e usabilità: interfacce curate, pensate per ridurre gli errori e i tempi di formazione, richiedono un investimento aggiuntivo che spesso si ripaga in produttività.</li><li>Sicurezza e requisiti normativi: gestire dati sensibili o rispettare specifici obblighi di settore aumenta le attività necessarie.</li></ul><p class="wp-block-paragraph">Una voce che molti sottovalutano è la manutenzione. Un software, infatti, non è un acquisto una tantum: va aggiornato, corretto e adattato quando cambiano le esigenze aziendali o le normative.</p><p class="wp-block-paragraph">Anche l&#039;infrastruttura incide sui costi ricorrenti. Con un approccio orientato allo sviluppo e cloud, ad esempio, puoi far crescere le risorse in base al reale utilizzo. In questo modo eviti di pagare in anticipo per una capacità che potresti non usare mai.</p><blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow"><p>Il preventivo più utile non è quello più basso, ma quello che ti spiega con chiarezza cosa stai pagando e perché.</p></blockquote><p class="wp-block-paragraph">Il modo più concreto per avere una stima realistica è partire da un confronto sui tuoi obiettivi e sui sistemi che già utilizzi. Raccontaci il processo che vuoi migliorare: possiamo aiutarti a definire priorità, ipotesi di intervento e un preventivo costruito sui tuoi numeri reali, non su cifre generiche.</p><h2 class="wp-block-heading">Come scegliere il partner giusto per lo sviluppo software su misura per aziende</h2><p class="wp-block-paragraph">Dopo aver chiarito esigenze, vantaggi, fasi e costi, resta la decisione più importante: a chi affidare il progetto. La qualità del fornitore incide sul risultato tanto quanto il budget. Un partner competente, infatti, riduce i rischi ed evita ritardi. Inoltre costruisce una soluzione che cresce con l&#039;azienda, invece di diventare un vincolo da rifare dopo pochi anni.</p><p class="wp-block-paragraph">Per valutare un potenziale fornitore, non fermarti al preventivo più basso. Concentrati piuttosto su elementi concreti che dicono molto sulla serietà del lavoro.</p><ul class="wp-block-list"><li>Esperienza dimostrabile: chiedi casi reali, referenze e progetti simili al tuo per settore o complessità.</li><li>Metodo di lavoro chiaro: come vengono gestite analisi, sviluppo, test e rilascio, e con quali tempi.</li><li>Comunicazione trasparente: un buon partner spiega le scelte in modo comprensibile, senza nascondersi dietro tecnicismi.</li><li>Gestione del cloud e della manutenzione: verifica come viene garantita continuità, sicurezza e assistenza dopo il rilascio.</li><li>Proprietà del codice e delle credenziali: assicurati di mantenere il controllo di ciò che è tuo.</li></ul><p class="wp-block-paragraph">Un altro segnale importante è la disponibilità del fornitore ad ascoltare prima di proporre. Chi parte subito con la soluzione, senza aver capito i tuoi processi, difficilmente costruirà qualcosa che ti serve davvero. La consulenza iniziale, infatti, serve proprio a questo: mettere a fuoco obiettivi, priorità e vincoli. Così si arriva a una proposta realistica e non a un preventivo generico.</p><blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow"><p>Il partner giusto non è quello che dice sempre di sì, ma quello che ti aiuta a capire cosa conviene davvero fare.</p></blockquote><p class="wp-block-paragraph">Con il nostro servizio di sviluppo e cloud accompagniamo le aziende dalla progettazione fino alla messa in esercizio della soluzione. Ci occupiamo sia della parte di sviluppo su misura sia dell&#039;infrastruttura cloud che la ospita. Questo ti permette di avere un unico interlocutore per l&#039;intero percorso, con maggiore chiarezza sui tempi e sulle responsabilità.</p><p class="wp-block-paragraph">Se stai valutando un progetto di sviluppo software su misura per aziende o vuoi capire se conviene partire, richiedi una consulenza. Analizzeremo insieme le tue esigenze e ti aiuteremo a definire la strada più adatta, senza impegno.</p>

<div class="wp-block-group scriba-cta"><div class="wp-block-group__inner-container is-layout-flow wp-block-group-is-layout-flow"><p><strong>Ti serve un supporto concreto?</strong> Scopri il nostro servizio <a href="https://renor.it/servizi/sviluppo-e-cloud/">Sviluppo e cloud</a> oppure <a href="https://renor.it/contatti/">contattaci</a> per una consulenza.</p></div></div>

<h2 class="wp-block-heading">Leggi anche</h2>

<ul class="wp-block-list"><li><a href="https://renor.it/blog/marketing-business-digitale/costo-integrazione-gestionale-con-sistemi-esterni-azienda/">Quanto costa integrare il gestionale con i sistemi esterni: guida ai costi per le aziende</a></li><li><a href="https://renor.it/blog/intelligenza-artificiale-algoritmi/agenti-ai-su-misura-per-pmi-costo/">Agenti AI su misura per PMI: quanto costano davvero e come valutare l&#8217;investimento</a></li></ul><p>L'articolo <a href="https://renor.it/blog/sviluppo-software-programmazione/sviluppo-software-su-misura-per-aziende/">Sviluppo software su misura per aziende: quando conviene e quanto costa</a> proviene da <a href="https://renor.it">RENOR &amp; Partners S.r.l.</a>.</p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Quanto costa sviluppare un&#8217;app mobile aziendale? Guida ai prezzi e ai fattori chiave</title>
		<link>https://renor.it/blog/sviluppo-software-programmazione/costo-sviluppo-app-mobile-per-aziende/</link>
		
		<dc:creator><![CDATA[Simone Renzi]]></dc:creator>
		<pubDate>Mon, 13 Jul 2026 08:55:59 +0000</pubDate>
				<category><![CDATA[Sviluppo Software & Programmazione]]></category>
		<category><![CDATA[automazione]]></category>
		<category><![CDATA[innovazione]]></category>
		<category><![CDATA[renor]]></category>
		<category><![CDATA[tecnologia]]></category>
		<guid isPermaLink="false">https://renor.it/blog/sviluppo-software-programmazione/costo-sviluppo-app-mobile-per-aziende/</guid>

					<description><![CDATA[<p>Scopri il costo sviluppo app mobile per aziende: fattori che incidono sul prezzo, fasce indicative e consigli pratici per pianificare il budget.</p>
<p>L'articolo <a href="https://renor.it/blog/sviluppo-software-programmazione/costo-sviluppo-app-mobile-per-aziende/">Quanto costa sviluppare un&#8217;app mobile aziendale? Guida ai prezzi e ai fattori chiave</a> proviene da <a href="https://renor.it">RENOR &amp; Partners S.r.l.</a>.</p>
]]></description>
										<content:encoded><![CDATA[<h2 class="wp-block-heading">Costo sviluppo app mobile per aziende: perché la domanda giusta non è &quot;quanto costa&quot; ma &quot;cosa ti serve&quot;</h2><p class="wp-block-paragraph">Il costo di sviluppo app mobile per aziende non è un numero fisso. Chiedere quanto costa un&#039;app aziendale è come chiedere quanto costa un veicolo: dipende se ti serve uno scooter per consegne in città o un mezzo per trasportare merci pesanti. Infatti, la cifra prende forma solo quando è chiaro il problema che l&#039;app deve risolvere. Per questo, prima di parlare di budget, conviene spostare l&#039;attenzione sull&#039;obiettivo di business.</p><p class="wp-block-paragraph">Un&#039;app che digitalizza un processo interno per venti dipendenti ha esigenze molto diverse da un&#039;app rivolta a migliaia di clienti finali. Infatti cambiano le funzionalità indispensabili, il livello di affidabilità richiesto e la gestione dei dati. Cambia anche la capacità di reggere i picchi di utilizzo. Sono queste scelte, dettate dai tuoi obiettivi, a determinare il costo, non un listino calato dall&#039;alto.</p><p class="wp-block-paragraph">Partire dalle esigenze reali ti permette anche di evitare due errori opposti e costosi. Da un lato, pagare per funzioni che non useranno mai. Dall&#039;altro, risparmiare su elementi che diventeranno colli di bottiglia appena l&#039;app crescerà. Ecco perché le domande più utili all&#039;inizio sono concrete:</p><ul class="wp-block-list"><li>Quale problema o attività l&#039;app deve semplificare, e per chi?</li><li>Chi la userà: dipendenti, clienti, fornitori? Quanti, e con quale frequenza?</li><li>Quali risultati misurabili ti aspetti nei primi sei-dodici mesi?</li><li>Come immagini la crescita dell&#039;utilizzo nel tempo?</li></ul><p class="wp-block-paragraph">Le risposte a queste domande orientano scelte tecniche altrimenti invisibili ma decisive per il costo. Parliamo, ad esempio, dell&#039;architettura di sviluppo e dell&#039;infrastruttura cloud su cui l&#039;app vivrà. Un impianto ben dimensionato, infatti, ti permette di partire con l&#039;essenziale e di scalare quando serve, senza rifare tutto da capo.</p><p class="wp-block-paragraph">È questo l&#039;approccio con cui affrontiamo lo sviluppo e il cloud: non un preventivo pensato prima di conoscerti, ma una soluzione costruita attorno a ciò che la tua azienda vuole davvero ottenere.</p><blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow"><p>Il prezzo non è il punto di partenza: è la conseguenza di scelte fatte bene sulla base dei tuoi obiettivi.</p></blockquote><h2 class="wp-block-heading">I fattori che determinano il costo di sviluppo di un&#039;app mobile per aziende</h2><p class="wp-block-paragraph">Un preventivo per un&#039;app non è mai un numero calato dall&#039;alto. Al contrario, è la somma di scelte concrete che riguardano cosa vuoi ottenere e in quale contesto opererà l&#039;applicazione. Capire quali variabili incidono sul prezzo, infatti, ti permette di leggere un&#039;offerta con occhio critico. Inoltre ti aiuta a confrontare fornitori diversi e a capire dove puoi risparmiare senza compromettere il risultato.</p><p class="wp-block-paragraph">Ecco le voci che pesano di più su un budget di sviluppo:</p><ul class="wp-block-list"><li>Piattaforme di destinazione: sviluppare per iOS, Android e web significa moltiplicare il lavoro. Coprire tutti i canali garantisce la massima diffusione, ma se il tuo pubblico usa prevalentemente un solo sistema, concentrarti su quello riduce i costi iniziali.</li><li>Complessità delle funzionalità: una schermata informativa costa molto meno di funzioni come pagamenti, chat in tempo reale o geolocalizzazione. Ogni funzione, infatti, aggiunge tempo di sviluppo e test.</li><li>Integrazioni con i tuoi sistemi: collegare l&#039;app al gestionale, all&#039;ERP o al CRM aziendale è spesso la parte più delicata. Dipende da quanto quei sistemi sono predisposti a dialogare con l&#039;esterno.</li><li>Design e UX: un&#039;interfaccia curata e coerente con la tua immagine aziendale richiede lavoro di progettazione. Non è un costo estetico: un&#039;app confusa viene abbandonata, vanificando l&#039;investimento.</li><li>Backend e cloud: è la parte invisibile all&#039;utente, cioè l&#039;infrastruttura che gestisce dati, utenti e logiche di business. La sua robustezza determina quanto l&#039;app reggerà nel tempo.</li><li>Sicurezza: proteggere i dati aziendali e quelli dei clienti comporta accorgimenti tecnici da prevedere fin dall&#039;inizio, soprattutto se tratti informazioni sensibili.</li></ul><p class="wp-block-paragraph">Molte di queste voci, inoltre, sono collegate tra loro: backend, cloud e sicurezza, ad esempio, vanno progettati insieme. Ecco perché un partner in grado di seguire sia lo sviluppo sia l&#039;infrastruttura cloud fa la differenza. In questo modo si evita che scelte prese su un fronte generino costi imprevisti sull&#039;altro.</p><blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow"><p>Quando leggi un preventivo, chiediti sempre a quale di questi fattori si riferisce ogni voce: è il modo più semplice per capire cosa stai davvero pagando.</p></blockquote><h2 class="wp-block-heading">Fasce di prezzo indicative: dall&#039;MVP all&#039;app enterprise</h2><p class="wp-block-paragraph">Una premessa è doverosa: ogni cifra che segue è un ordine di grandezza, non un preventivo. Serve a capire in quale fascia si colloca la tua idea, così da affrontare le trattative con aspettative realistiche. Inoltre, i costi variano in base ai fattori già visti, come piattaforme, integrazioni, sicurezza e mantenimento.</p><p class="wp-block-paragraph">Per orientarti, distinguiamo quindi tre tipologie ricorrenti di progetto.</p><ul class="wp-block-list"><li>App semplice / MVP: una prima versione con poche funzioni essenziali, pensata per validare l&#039;idea sul mercato. Indicativamente 10.000–30.000 €. Poca logica lato server, poche integrazioni, interfaccia essenziale ma curata.</li><li>App gestionale con backend: gestisce dati, utenti e processi aziendali, con un server dedicato, area di amministrazione e alcune integrazioni. Indicativamente 30.000–80.000 €. È la fascia più comune per le PMI che digitalizzano un flusso di lavoro.</li><li>App enterprise complessa: molte funzionalità, ruoli e permessi articolati, integrazioni con più sistemi, requisiti di sicurezza elevati. Da 80.000 € in su, senza un tetto preciso perché dipende dall&#039;ampiezza del progetto.</li></ul><p class="wp-block-paragraph">Un aspetto spesso sottovalutato è il costo dell&#039;infrastruttura. Un&#039;app gestionale o enterprise, infatti, non vive solo sul telefono dell&#039;utente: ha bisogno di un backend affidabile e di un ambiente cloud dimensionato sui picchi di traffico. Questa voce incide sia sullo sviluppo iniziale sia sui costi ricorrenti mensili, e va valutata fin dall&#039;inizio.</p><blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow"><p>Il prezzo di listino non esiste: esiste il prezzo del tuo progetto, definito da cosa deve fare e da quanto deve durare nel tempo.</p></blockquote><p class="wp-block-paragraph">Il nostro approccio, quindi, è affiancare lo sviluppo dell&#039;applicazione alla progettazione del cloud che la sostiene. In questo modo il preventivo tiene conto dell&#039;intero quadro, non solo del software visibile all&#039;utente. Prima di stimare, conviene sempre inquadrare bene il perimetro: una richiesta chiara riduce il margine di incertezza.</p><h2 class="wp-block-heading">Nativa, ibrida o web app: come la scelta tecnologica incide sul budget</h2><figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="800" height="800" src="https://renor.it/wp-content/uploads/2026/07/quanto-costa-sviluppare-unapp-mobile-aziendale-guida-ai-prezzi-e-ai-fattori-chiave-fig-1-800x800.png" alt="Team di sviluppo al lavoro sulla progettazione di un&apos;app mobile aziendale" class="wp-image-3029" srcset="https://renor.it/wp-content/uploads/2026/07/quanto-costa-sviluppare-unapp-mobile-aziendale-guida-ai-prezzi-e-ai-fattori-chiave-fig-1-800x800.png 800w, https://renor.it/wp-content/uploads/2026/07/quanto-costa-sviluppare-unapp-mobile-aziendale-guida-ai-prezzi-e-ai-fattori-chiave-fig-1-150x150.png 150w, https://renor.it/wp-content/uploads/2026/07/quanto-costa-sviluppare-unapp-mobile-aziendale-guida-ai-prezzi-e-ai-fattori-chiave-fig-1-300x300.png 300w" sizes="auto, (max-width: 800px) 100vw, 800px" /></figure><p class="wp-block-paragraph">Dietro ogni app c&#039;è una decisione tecnica che pesa sul budget più di quanto si immagini: l&#039;approccio di sviluppo. Non esiste una scelta &quot;migliore&quot; in assoluto, ma quella più adatta ai tuoi obiettivi. Capire le differenze, infatti, ti permette di dialogare meglio con chi svilupperà il progetto.</p><p class="wp-block-paragraph">Le tre strade principali sono lo sviluppo nativo, quello ibrido e la web app. Ognuna, tuttavia, ha implicazioni diverse su costi iniziali, tempi e spese di manutenzione nel tempo.</p><ul class="wp-block-list"><li>App nativa: sviluppata separatamente per iOS e Android, con linguaggi specifici per ciascuna piattaforma. Offre le prestazioni migliori e l&#039;accesso completo alle funzionalità del dispositivo. Costa di più perché, di fatto, si costruiscono due applicazioni distinte.</li><li>App ibrida o cross-platform: un unico codice base che funziona su entrambi i sistemi operativi. Riduce sensibilmente costi e tempi di sviluppo e semplifica gli aggiornamenti. È spesso il miglior compromesso tra qualità e investimento.</li><li>Web app: accessibile dal browser senza installazione dagli store. È la soluzione più economica e rapida, ideale per strumenti gestionali interni, ma con accesso limitato alle funzioni del dispositivo.</li></ul><p class="wp-block-paragraph">Il punto spesso trascurato è la manutenzione. Un&#039;app nativa, infatti, comporta due basi di codice da aggiornare a ogni nuova versione dei sistemi operativi. Questo è un costo ricorrente che, sul lungo periodo, può superare quello iniziale. L&#039;approccio ibrido, invece, concentra questi interventi su un solo codice, contenendo la spesa nel tempo.</p><blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow"><p>La domanda decisiva non è &quot;quale tecnologia è più potente&quot;, ma &quot;quanto mi costerà mantenere questa app tra due anni?&quot;.</p></blockquote><p class="wp-block-paragraph">A questa scelta si aggiunge l&#039;infrastruttura che sostiene l&#039;app: dove risiedono i dati, come scala il servizio, quanto è affidabile. È qui che <a href="https://renor.it/servizi/sviluppo-e-cloud/">sviluppo e cloud</a> lavorano insieme. Infatti, un&#039;architettura pensata bene fin dall&#039;inizio evita costose riscritture future.</p><h2 class="wp-block-heading">I costi nascosti: manutenzione, aggiornamenti e cloud</h2><p class="wp-block-paragraph">Il preventivo di sviluppo racconta solo una parte della storia. Il giorno in cui l&#039;app viene pubblicata sugli store, infatti, non segna la fine dell&#039;investimento, ma l&#039;inizio di una spesa ricorrente. Un&#039;app mobile non è un progetto &quot;chiavi in mano&quot;: è un prodotto vivo, che va mantenuto per continuare a generare valore.</p><p class="wp-block-paragraph">Ci sono diverse voci che tendono a sfuggire alla pianificazione iniziale. Sommate, incidono in modo significativo sul costo reale nel tempo.</p><ul class="wp-block-list"><li>Hosting e infrastruttura cloud: la maggior parte delle app si appoggia a un backend che deve restare sempre attivo. Questa spesa cresce con il numero di utenti.</li><li>Aggiornamenti dei sistemi operativi: Apple e Google rilasciano nuove versioni ogni anno. Senza adeguamenti periodici, l&#039;app rischia di smettere di funzionare.</li><li>Costi degli store: gli account sviluppatore Apple e Google prevedono canoni annuali per mantenere la pubblicazione.</li><li>Sicurezza e correzioni: vanno risolti i bug segnalati dagli utenti e aggiornate le librerie, a tutela dei dati aziendali.</li></ul><p class="wp-block-paragraph">Ecco un&#039;indicazione realistica: i costi di manutenzione annuale si aggirano spesso tra il 15% e il 20% del budget iniziale di sviluppo. Ignorare questa voce, quindi, significa costruire su fondamenta destinate a deteriorarsi.</p><blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow"><p>Un&#039;app non aggiornata non è un investimento fermo: è un investimento che perde valore ogni mese.</p></blockquote><p class="wp-block-paragraph">Per questo la scelta del fornitore va valutata guardando oltre la consegna. Serve, infatti, un partner in grado di seguire l&#039;app nel tempo, dallo sviluppo alla gestione dell&#039;infrastruttura. È esattamente l&#039;approccio del nostro servizio di sviluppo e cloud: seguire il prodotto in modo continuativo, così che ogni intervento faccia parte di un percorso pianificato.</p><h2 class="wp-block-heading">Come ottenere un preventivo su misura per il costo sviluppo app mobile per aziende</h2><figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="800" height="800" src="https://renor.it/wp-content/uploads/2026/07/quanto-costa-sviluppare-unapp-mobile-aziendale-guida-ai-prezzi-e-ai-fattori-chiave-fig-2-800x800.png" alt="Applicazione mobile gestionale visualizzata su uno smartphone in contesto aziendale" class="wp-image-3030" srcset="https://renor.it/wp-content/uploads/2026/07/quanto-costa-sviluppare-unapp-mobile-aziendale-guida-ai-prezzi-e-ai-fattori-chiave-fig-2-800x800.png 800w, https://renor.it/wp-content/uploads/2026/07/quanto-costa-sviluppare-unapp-mobile-aziendale-guida-ai-prezzi-e-ai-fattori-chiave-fig-2-150x150.png 150w, https://renor.it/wp-content/uploads/2026/07/quanto-costa-sviluppare-unapp-mobile-aziendale-guida-ai-prezzi-e-ai-fattori-chiave-fig-2-300x300.png 300w" sizes="auto, (max-width: 800px) 100vw, 800px" /></figure><p class="wp-block-paragraph">Arrivare a un preventivo affidabile non significa chiedere un numero al primo fornitore disponibile. Significa, invece, mettere il fornitore nelle condizioni di capire davvero cosa vi serve. Più il quadro iniziale è chiaro, infatti, più la stima sarà realistica. La differenza tra un progetto che rispetta budget e tempi e uno che sfugge di mano si gioca quasi sempre nelle prime settimane.</p><p class="wp-block-paragraph">Il primo passo concreto è raccogliere e mettere per iscritto i requisiti. Non serve un documento tecnico: bastano risposte chiare ad alcune domande di fondo, che potete preparare internamente prima ancora di parlare con un partner.</p><ul class="wp-block-list"><li>Qual è il problema che l&#039;app deve risolvere e per chi (clienti, dipendenti, rete vendita)?</li><li>Quali sono le 3-5 funzionalità irrinunciabili al lancio e quali possono aspettare?</li><li>Quali sistemi già in uso dovranno dialogare con l&#039;app (gestionale, CRM, e-commerce)?</li><li>Che volumi di utenti e dati prevedete nei primi 12-18 mesi?</li><li>Qual è il budget di massima e la data entro cui l&#039;app dovrebbe essere operativa?</li></ul><p class="wp-block-paragraph">Con questi elementi in mano, il secondo passo è un&#039;analisi di fattibilità. È una fase breve ma decisiva: serve a validare le ipotesi tecniche e a stimare l&#039;effort in modo credibile. Partire da un MVP ben definito, infatti, permette di distribuire l&#039;investimento nel tempo, invece di concentrarlo tutto in un&#039;unica scommessa iniziale.</p><blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow"><p>Un preventivo su misura non è un preventivo più economico: è un preventivo che sai perché stai pagando.</p></blockquote><p class="wp-block-paragraph">Il terzo passo, quindi, è affidarsi a chi può accompagnarvi dall&#039;idea alla messa in produzione. Il servizio di Sviluppo e cloud di RENOR &amp; Partners nasce proprio per unire la progettazione dell&#039;applicazione alla gestione dell&#039;infrastruttura, con un approccio di <a href="https://renor.it/servizi/consulenza-strategica/">consulenza strategica</a> che parte dai vostri obiettivi di business.</p><p class="wp-block-paragraph">Se state valutando il costo di sviluppo di un&#039;app mobile per la vostra azienda, il modo più efficace per trasformare le stime di questo articolo in numeri concreti è confrontarvi con noi. Partiamo dai vostri requisiti, li traduciamo in un&#039;analisi di fattibilità e vi restituiamo un percorso chiaro, con costi e priorità definiti.</p>

<div class="wp-block-group scriba-cta"><div class="wp-block-group__inner-container is-layout-flow wp-block-group-is-layout-flow"><p><strong>Ti serve un supporto concreto?</strong> Scopri il nostro servizio <a href="https://renor.it/servizi/sviluppo-e-cloud/">Sviluppo e cloud</a> oppure <a href="https://renor.it/contatti/">contattaci</a> per una consulenza.</p></div></div>

<h2 class="wp-block-heading">Leggi anche</h2>

<ul class="wp-block-list"><li><a href="https://renor.it/servizi/consulenza-it/">Consulenza IT</a></li></ul><p>L'articolo <a href="https://renor.it/blog/sviluppo-software-programmazione/costo-sviluppo-app-mobile-per-aziende/">Quanto costa sviluppare un&#8217;app mobile aziendale? Guida ai prezzi e ai fattori chiave</a> proviene da <a href="https://renor.it">RENOR &amp; Partners S.r.l.</a>.</p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Preventivo software gestionale personalizzato: guida ai costi per le aziende</title>
		<link>https://renor.it/blog/sviluppo-software-programmazione/preventivo-software-gestionale-personalizzato-aziende/</link>
		
		<dc:creator><![CDATA[Simone Renzi]]></dc:creator>
		<pubDate>Sun, 12 Jul 2026 09:08:31 +0000</pubDate>
				<category><![CDATA[Sviluppo Software & Programmazione]]></category>
		<category><![CDATA[automazione]]></category>
		<category><![CDATA[innovazione]]></category>
		<category><![CDATA[renor]]></category>
		<category><![CDATA[software gestionale]]></category>
		<guid isPermaLink="false">https://renor.it/blog/sviluppo-software-programmazione/preventivo-software-gestionale-personalizzato-aziende/</guid>

					<description><![CDATA[<p>Richiedi un preventivo software gestionale personalizzato aziende: scopri costi reali, voci di spesa e come ottenere una stima accurata su misura.</p>
<p>L'articolo <a href="https://renor.it/blog/sviluppo-software-programmazione/preventivo-software-gestionale-personalizzato-aziende/">Preventivo software gestionale personalizzato: guida ai costi per le aziende</a> proviene da <a href="https://renor.it">RENOR &amp; Partners S.r.l.</a>.</p>
]]></description>
										<content:encoded><![CDATA[<h2 class="wp-block-heading">Preventivo software gestionale personalizzato aziende: quando conviene il su misura</h2><p class="wp-block-paragraph">Se state per richiedere un preventivo software gestionale personalizzato aziende, è utile chiarire subito un punto: la scelta giusta non dipende solo dal prezzo. Dipende soprattutto da quanto lo strumento rispecchia il modo in cui la vostra azienda lavora davvero. Un gestionale standard, infatti, è un prodotto già pronto, acquistabile a listino o in abbonamento. Copre esigenze comuni a molte imprese: contabilità, magazzino, fatturazione, anagrafiche clienti. Una soluzione su misura, invece, viene progettata partendo dai vostri processi specifici.</p><p class="wp-block-paragraph">Il pacchetto standard ha vantaggi concreti: costi iniziali contenuti, tempi di avvio rapidi, aggiornamenti e assistenza garantiti dal fornitore. Il limite, però, è che chiede a voi di adattarvi al software, non il contrario. Finché i vostri processi rientrano negli schemi previsti, infatti, funziona bene. Quando invece cominciate ad accumulare fogli di calcolo paralleli, passaggi manuali e &quot;trucchi&quot; per far quadrare le cose, state già pagando un costo nascosto.</p><p class="wp-block-paragraph">La soluzione su misura conviene quando la personalizzazione non è un capriccio, ma un vantaggio competitivo. Ecco i segnali più chiari:</p><ul class="wp-block-list"><li>Avete flussi di lavoro particolari che nessun pacchetto standard riesce a rappresentare senza forzature.</li><li>Usate già diversi programmi che non dialogano tra loro e volete un unico punto di verità sui dati.</li><li>Prevedete crescita o cambiamenti frequenti, quindi vi serve uno strumento che evolva con l&#039;azienda.</li><li>Il vostro modo di lavorare è parte del valore che offrite ai clienti e non volete appiattirlo su uno standard.</li></ul><p class="wp-block-paragraph">Al contrario, se i vostri processi sono lineari e comuni al settore, un prodotto pronto resta spesso la scelta più razionale. In questo caso, infatti, chiedere un preventivo personalizzato avrebbe poco senso. Esiste comunque un&#039;opzione intermedia, piuttosto frequente: partire da una base solida e costruire su misura solo le parti che fanno davvero la differenza.</p><p class="wp-block-paragraph">È qui che entra in gioco un partner di sviluppo. Grazie ad attività di <a href="https://renor.it/servizi/sviluppo-e-cloud/">sviluppo e cloud</a>, infatti, è possibile realizzare un gestionale costruito sui vostri processi e reso accessibile in modo scalabile. Così lo strumento cresce insieme all&#039;azienda, senza dover ripartire da zero a ogni cambiamento.</p><blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow"><p>La domanda giusta non è &quot;quanto costa il su misura&quot;, ma &quot;quanto mi costa continuare ad adattare l&#039;azienda a uno strumento che non la rappresenta&quot;.</p></blockquote><h2 class="wp-block-heading">Quali fattori determinano il costo di un preventivo software gestionale personalizzato per aziende</h2><p class="wp-block-paragraph">Quando si richiede un preventivo per un software gestionale personalizzato, la prima domanda è quasi sempre la stessa: quanto costa? La risposta onesta è che il prezzo non è un numero fisso. È piuttosto il risultato di alcune variabili concrete. Capire quali sono, infatti, aiuta a leggere un&#039;offerta con occhio critico e a distinguere un preventivo serio da uno improvvisato.</p><p class="wp-block-paragraph">Ecco i fattori che incidono maggiormente sull&#039;investimento finale:</p><ul class="wp-block-list"><li>Numero di moduli e funzionalità: un gestionale che copre solo la fatturazione ha un costo molto diverso da uno che gestisce anche magazzino, vendite, produzione e reportistica. Più aree coprite, più tempo di sviluppo serve.</li><li>Integrazioni con i sistemi esistenti: collegare il nuovo software a strumenti già in uso richiede lavoro tecnico dedicato. Ogni integrazione, infatti, va progettata e testata singolarmente.</li><li>Numero e tipologia di utenti: conta quante persone useranno il gestionale e con quali permessi. Gestire ruoli diversi e molti utenti contemporanei aumenta la complessità.</li><li>Complessità dei processi aziendali: un flusso di lavoro lineare si traduce in uno sviluppo più snello. Processi con molte eccezioni richiedono invece un&#039;analisi più approfondita.</li><li>Personalizzazioni specifiche: interfacce su misura, calcoli particolari, documenti generati secondo le vostre esigenze. Ogni elemento &quot;tagliato&quot; sul vostro modo di lavorare pesa sul preventivo.</li><li>Manutenzione e assistenza: il costo non finisce alla consegna. Aggiornamenti e supporto continuo vanno considerati nel budget, spesso come canone periodico.</li></ul><p class="wp-block-paragraph">Un altro elemento che influisce sui costi è la modalità di rilascio del software. Con un approccio di sviluppo e cloud, infatti, l&#039;applicazione viene resa disponibile online. Questo sposta parte della spesa da un investimento iniziale in infrastruttura a un modello più flessibile e scalabile nel tempo.</p><p class="wp-block-paragraph">Il consiglio pratico, quindi, è chiedere sempre un preventivo che espliciti queste voci separatamente. Un&#039;offerta trasparente, infatti, vi permette di capire dove state investendo. Potrete così decidere cosa realizzare subito e cosa rimandare, mantenendo il controllo sul budget.</p><h2 class="wp-block-heading">Come leggere un preventivo: voci di spesa e range di prezzo</h2><p class="wp-block-paragraph">Un preventivo ben fatto non è un unico numero finale. È piuttosto un documento che scompone il progetto in voci chiare. Questo vi permette di capire dove vanno i vostri soldi e di confrontare offerte diverse in modo corretto. Di seguito trovate le voci che ricorrono più spesso, con fasce di prezzo puramente indicative: servono a orientarvi, non a definire un listino, perché ogni cifra dipende dalla complessità del vostro progetto.</p><ul class="wp-block-list"><li>Analisi e progettazione: la fase iniziale in cui si mappano processi e requisiti. Spesso vale il 10-20% del totale (indicativamente 2.000-10.000 €). È denaro ben speso, perché riduce sorprese e rilavorazioni.</li><li>Sviluppo su misura: la voce più consistente. Per progetti contenuti si parte da alcune migliaia di euro, mentre soluzioni articolate possono superare le decine di migliaia.</li><li>Licenze software: costi di eventuali componenti o database di terze parti, a volte una tantum, a volte annuali.</li><li>Cloud e infrastruttura: i costi per ospitare l&#039;applicativo, in genere mensili o annuali. Vanno considerati come spesa ricorrente, non una tantum.</li><li>Formazione: le ore dedicate a far usare bene il gestionale al vostro team. Spesso sottovalutata, incide molto sul ritorno dell&#039;investimento.</li><li>Assistenza e manutenzione: canone periodico per aggiornamenti e supporto. Indicativamente il 15-25% annuo del costo di sviluppo.</li></ul><p class="wp-block-paragraph">Quando confrontate più offerte, quindi, non fermatevi al totale: verificate che tutte includano le stesse voci. Un preventivo più basso che omette formazione o assistenza, infatti, raramente è davvero più conveniente.</p><blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow"><p>Distinguete sempre tra costi una tantum (analisi, sviluppo) e costi ricorrenti (cloud, licenze annuali, assistenza): sono queste ultime a determinare la spesa nel tempo.</p></blockquote><p class="wp-block-paragraph">Nel nostro caso, sviluppo e cloud sono gestiti insieme. Questo consente di leggere in un unico preventivo sia la parte di realizzazione su misura sia i costi ricorrenti dell&#039;infrastruttura, con maggiore chiarezza su ciò che pagherete oggi e nel tempo.</p><h2 class="wp-block-heading">Costi nascosti e ROI: perché il prezzo iniziale non basta</h2><p class="wp-block-paragraph">La cifra indicata in fondo al preventivo racconta solo una parte della storia. Un gestionale, infatti, non è un acquisto che si esaurisce alla consegna: è un sistema che accompagna l&#039;azienda negli anni. Concentrarsi solo sul costo di sviluppo iniziale, quindi, porta spesso a sottostimare la spesa reale. Soprattutto, fa perdere di vista ciò che conta davvero: quanto quel software vi farà guadagnare o risparmiare nel tempo.</p><p class="wp-block-paragraph">Prima di firmare, quindi, chiedete al fornitore un quadro chiaro delle voci ricorrenti. Sono queste, più del prezzo di partenza, a determinare il costo effettivo su un orizzonte di tre o cinque anni.</p><ul class="wp-block-list"><li>Manutenzione: correzione di malfunzionamenti e piccoli adeguamenti dopo il rilascio.</li><li>Aggiornamenti: adeguamenti normativi, evoluzioni funzionali e compatibilità con altri strumenti.</li><li>Hosting: i costi dell&#039;infrastruttura su cui gira il software, con canoni variabili in base a spazio e prestazioni.</li><li>Formazione: l&#039;affiancamento alle persone che useranno il gestionale ogni giorno, spesso decisivo per l&#039;effettiva adozione.</li></ul><p class="wp-block-paragraph">Una volta messe a fuoco queste voci, il ragionamento va ribaltato. La domanda non è più &quot;quanto costa?&quot;, ma &quot;cosa mi restituisce?&quot;. Il ritorno sull&#039;investimento di un gestionale su misura, infatti, si misura in termini concreti: ore di lavoro manuale eliminate, errori ridotti, processi automatizzati.</p><p class="wp-block-paragraph">Se un&#039;attività che occupava un collaboratore per diverse ore a settimana viene automatizzata, quel tempo liberato ha un valore economico preciso. Per questo, quindi, conviene sempre guardare oltre il prezzo iniziale.</p><blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow"><p>Un software costoso che fa risparmiare 20 ore al mese conviene più di uno economico che non cambia il modo di lavorare.</p></blockquote><p class="wp-block-paragraph">Proprio per questo, lo sviluppo e il cloud vanno considerati insieme. Costruire una soluzione su misura e ospitarla su un&#039;infrastruttura affidabile, infatti, significa avere un costo ricorrente prevedibile, senza sorprese. Valutate quindi ogni preventivo non come una spesa isolata, ma come un investimento di cui stimare il rientro nel tempo.</p><h2 class="wp-block-heading">Come preparare la richiesta di preventivo per una stima accurata</h2><figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="800" height="800" src="https://renor.it/wp-content/uploads/2026/07/preventivo-software-gestionale-personalizzato-guida-ai-costi-per-le-aziende-fig-1-800x800.png" alt="Imprenditore e consulente discutono un preventivo software gestionale in ufficio" class="wp-image-3025" srcset="https://renor.it/wp-content/uploads/2026/07/preventivo-software-gestionale-personalizzato-guida-ai-costi-per-le-aziende-fig-1-800x800.png 800w, https://renor.it/wp-content/uploads/2026/07/preventivo-software-gestionale-personalizzato-guida-ai-costi-per-le-aziende-fig-1-150x150.png 150w, https://renor.it/wp-content/uploads/2026/07/preventivo-software-gestionale-personalizzato-guida-ai-costi-per-le-aziende-fig-1-300x300.png 300w" sizes="auto, (max-width: 800px) 100vw, 800px" /></figure><p class="wp-block-paragraph">Un preventivo vale quanto le informazioni su cui si basa. Se fornite ai fornitori una descrizione vaga, infatti, riceverete numeri altrettanto vaghi, difficili da confrontare tra loro. Investire qualche giornata nella preparazione della richiesta, quindi, è il modo più efficace per ottenere stime realistiche e paragonabili.</p><p class="wp-block-paragraph">Il punto di partenza è mappare i processi che il software dovrà supportare. Non si tratta di scrivere un capitolato tecnico, ma di descrivere come lavorate oggi: chi fa cosa, con quali passaggi, dove nascono errori o perdite di tempo. Questa fotografia, infatti, permette al fornitore di capire la complessità effettiva e di dimensionare correttamente l&#039;offerta.</p><p class="wp-block-paragraph">Una volta raccolti i requisiti, il passaggio decisivo è definire le priorità. Raramente serve realizzare tutto subito. Distinguere ciò che è indispensabile fin dal primo rilascio da ciò che può arrivare dopo, infatti, vi consente di controllare l&#039;investimento iniziale e di partire prima.</p><ul class="wp-block-list"><li>Obiettivi di business: quale problema volete risolvere e come misurerete il risultato.</li><li>Processi coinvolti: elenco delle attività da digitalizzare e dei reparti interessati.</li><li>Numeri di riferimento: utenti previsti, volumi di dati e documenti, picchi di lavoro.</li><li>Integrazioni necessarie: gestionale contabile, e-commerce, strumenti già in uso.</li><li>Priorità: funzioni indispensabili separate da quelle desiderabili.</li><li>Vincoli: tempi, budget indicativo, eventuali requisiti normativi.</li></ul><p class="wp-block-paragraph">Fornire questi elementi a tutti i fornitori nello stesso formato, quindi, è ciò che rende i preventivi davvero comparabili: valuterete offerte sullo stesso perimetro, non mele con pere.</p><blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow"><p>Una consulenza iniziale ben condotta spesso vale più del preventivo stesso: aiuta a chiarire le priorità e a evitare investimenti su funzioni che non servono.</p></blockquote><p class="wp-block-paragraph">Se non avete competenze tecniche interne, coinvolgere fin da subito un partner di sviluppo e cloud vi permette di trasformare esigenze operative in requisiti concreti. Questo confronto preliminare, infatti, chiarisce cosa è realmente utile costruire, riducendo il rischio di sorprese quando arriverà il preventivo definitivo.</p><h2 class="wp-block-heading">Affidarsi a un partner tecnologico: come lavora RENOR &amp; Partners</h2><p class="wp-block-paragraph">Scegliere chi svilupperà il vostro gestionale è una decisione importante quanto definire il budget. Un buon partner tecnologico, infatti, non si limita a scrivere codice: ascolta le esigenze dell&#039;azienda e traduce i processi in soluzioni concrete. Accompagna il progetto dalla prima analisi fino alla messa in produzione e oltre. È questo l&#039;approccio con cui operiamo in RENOR &amp; Partners.</p><p class="wp-block-paragraph">Prima di proporre una stima economica, dedichiamo tempo a comprendere come lavora davvero la vostra impresa. Analizziamo i flussi operativi, individuiamo le priorità e definiamo insieme cosa è indispensabile fin dal primo rilascio. Questo metodo permette di contenere i costi iniziali ed evitare funzionalità inutili. Il risultato, infatti, è un preventivo software gestionale personalizzato aziende aderente alla realtà, senza sorprese in corso d&#039;opera.</p><p class="wp-block-paragraph">Il nostro servizio di Sviluppo e cloud si occupa della realizzazione del software su misura e della sua gestione in ambiente cloud. Questo garantisce accessibilità, continuità operativa e scalabilità nel tempo. A questo affianchiamo la <a href="https://renor.it/servizi/consulenza-it/">Consulenza IT</a>, utile per chi ha bisogno di supporto anche nelle scelte strategiche: quali strumenti integrare, come organizzare l&#039;infrastruttura, come far crescere il sistema insieme all&#039;azienda.</p><p class="wp-block-paragraph">Lavorare con un unico interlocutore per sviluppo, cloud e consulenza semplifica la comunicazione e riduce i tempi. Chi conosce il progetto nel suo insieme, infatti, può prendere decisioni più rapide e coerenti. Si evitano così quei costi nascosti che spesso nascono dalla frammentazione tra fornitori diversi.</p><ul class="wp-block-list"><li>Analisi dei processi e definizione delle priorità prima del preventivo</li><li>Sviluppo del gestionale su misura con gestione in cloud</li><li>Consulenza IT per accompagnare le scelte tecnologiche nel tempo</li><li>Un unico referente per tutte le fasi del progetto</li></ul><p class="wp-block-paragraph">State valutando un gestionale personalizzato e volete capire quale investimento comporta nel vostro caso? Il modo più concreto per iniziare, infatti, è confrontarsi su obiettivi e processi reali. Contattateci per richiedere un preventivo software gestionale personalizzato aziende: analizzeremo insieme le vostre esigenze e vi forniremo una stima chiara e argomentata.</p>

<div class="wp-block-group scriba-cta"><div class="wp-block-group__inner-container is-layout-flow wp-block-group-is-layout-flow"><p><strong>Ti serve un supporto concreto?</strong> Scopri il nostro servizio <a href="https://renor.it/servizi/sviluppo-e-cloud/">Sviluppo e cloud</a> oppure <a href="https://renor.it/contatti/">contattaci</a> per una consulenza.</p></div></div>

<h2 class="wp-block-heading">Leggi anche</h2>

<ul class="wp-block-list"><li><a href="https://renor.it/blog/sviluppo-software-programmazione/preventivo-sviluppo-applicazione-web-aziendale/">Preventivo per lo sviluppo di un&#8217;applicazione web aziendale: guida completa ai costi</a></li></ul><p>L'articolo <a href="https://renor.it/blog/sviluppo-software-programmazione/preventivo-software-gestionale-personalizzato-aziende/">Preventivo software gestionale personalizzato: guida ai costi per le aziende</a> proviene da <a href="https://renor.it">RENOR &amp; Partners S.r.l.</a>.</p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Preventivo per lo sviluppo di un&#8217;applicazione web aziendale: guida completa ai costi</title>
		<link>https://renor.it/blog/sviluppo-software-programmazione/preventivo-sviluppo-applicazione-web-aziendale/</link>
		
		<dc:creator><![CDATA[Simone Renzi]]></dc:creator>
		<pubDate>Tue, 07 Jul 2026 08:53:25 +0000</pubDate>
				<category><![CDATA[Sviluppo Software & Programmazione]]></category>
		<category><![CDATA[innovazione]]></category>
		<category><![CDATA[lead generation]]></category>
		<category><![CDATA[renor]]></category>
		<category><![CDATA[tecnologia]]></category>
		<guid isPermaLink="false">https://renor.it/blog/sviluppo-software-programmazione/preventivo-sviluppo-applicazione-web-aziendale/</guid>

					<description><![CDATA[<p>Vuoi un preventivo sviluppo applicazione web aziendale? Scopri le variabili che determinano il prezzo e come confrontare le offerte in modo consapevole.</p>
<p>L'articolo <a href="https://renor.it/blog/sviluppo-software-programmazione/preventivo-sviluppo-applicazione-web-aziendale/">Preventivo per lo sviluppo di un&#8217;applicazione web aziendale: guida completa ai costi</a> proviene da <a href="https://renor.it">RENOR &amp; Partners S.r.l.</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<h2 id="h-preventivo-sviluppo-applicazione-web-aziendale-quanto-costa-davvero" class="wp-block-heading">Preventivo sviluppo applicazione web aziendale: quanto costa davvero?</h2>



<p class="wp-block-paragraph">Chi deve richiedere un preventivo per lo sviluppo di un&#8217;applicazione web aziendale si pone sempre la stessa domanda: quanto costa? La risposta onesta è: dipende. Non si tratta di una scappatoia, ma della realtà di un lavoro su misura. Infatti, un&#8217;applicazione web aziendale non è un prodotto a scaffale con un prezzo fisso. È uno strumento costruito attorno ai processi e agli obiettivi della vostra impresa. Per questo motivo, due preventivi apparentemente simili possono differire in modo significativo.</p>



<p class="wp-block-paragraph">In generale, il budget necessario dipende da alcune variabili concrete. Queste incidono in modo diretto sul tempo di lavoro. Di conseguenza, incidono anche sul costo finale. Conoscerle in anticipo vi permette di leggere un preventivo con occhio critico. Inoltre, vi aiuta a confrontare i fornitori sulla base di elementi reali, non solo del prezzo esposto.</p>



<ul class="wp-block-list">
<li>La complessità delle funzionalità richieste e il numero di flussi di lavoro da gestire</li>



<li>Il numero di utenti previsti e i livelli di accesso o autorizzazione</li>



<li>Le integrazioni con sistemi già in uso, come gestionali, CRM o strumenti di fatturazione</li>



<li>Le scelte relative all&#8217;infrastruttura, all&#8217;affidabilità e alla scalabilità della soluzione</li>



<li>La manutenzione e l&#8217;assistenza previste dopo il rilascio</li>
</ul>



<p class="wp-block-paragraph">In questo articolo non troverete una cifra magica, perché sarebbe fuorviante. Vi accompagneremo, invece, attraverso le voci che compongono un preventivo sviluppo applicazione web aziendale. Così potrete capire dove nascono i costi. Potrete anche capire quali sono negoziabili e su cosa non conviene risparmiare.</p>



<p class="wp-block-paragraph">L&#8217;obiettivo, quindi, è mettervi nella condizione di dialogare con qualsiasi fornitore da una posizione informata. In questo modo riconoscerete le proposte serie da quelle costruite solo per attirare con un prezzo basso.</p>



<p class="wp-block-paragraph">Un buon partner tecnologico, del resto, non si limita a scrivere codice. Si occupa dello sviluppo dell&#8217;applicazione e del cloud su cui questa vivrà. Inoltre, valuta insieme a voi le soluzioni più adatte al vostro contesto. Proprio questa visione d&#8217;insieme fa la differenza tra una spesa e un investimento che genera valore nel tempo.</p>



<h2 id="h-i-fattori-che-determinano-il-prezzo-di-un-preventivo-per-applicazioni-web" class="wp-block-heading">I fattori che determinano il prezzo di un preventivo per applicazioni web</h2>



<p class="wp-block-paragraph">Un preventivo per lo sviluppo di un&#8217;applicazione web non è mai un numero fisso. È il risultato di scelte precise. Queste scelte riguardano cosa deve fare il software, quante persone lo useranno e con quali sistemi dovrà dialogare. Capire quali sono queste variabili aiuta a leggere un&#8217;offerta con occhio critico. Inoltre, permette di distinguere ciò che fa davvero lievitare il budget da ciò che è superfluo.</p>



<ul class="wp-block-list">
<li>Complessità delle funzionalità: una piattaforma con poche schermate e flussi lineari costa meno di un&#8217;applicazione ricca di automazioni, calcoli, ruoli utente differenziati e logiche di business articolate. Ogni funzione aggiuntiva significa progettazione, sviluppo e test.</li>



<li>Numero di utenti e carico previsto: un gestionale usato da dieci persone ha esigenze diverse da un portale con migliaia di accessi simultanei. Più utenti significano maggiore attenzione alle prestazioni e all&#8217;infrastruttura.</li>



<li>Integrazioni con gestionali ed ERP esistenti: collegare l&#8217;applicazione ai sistemi già in azienda, come contabilità, magazzino o CRM, è spesso una delle voci più impegnative. Serve infatti far comunicare tecnologie diverse in modo affidabile.</li>



<li>Design e UX: un&#8217;interfaccia curata, intuitiva e coerente riduce gli errori e i tempi di formazione, ma richiede lavoro dedicato. È un investimento che si ripaga nell&#8217;uso quotidiano.</li>



<li>Sicurezza: protezione dei dati, gestione degli accessi e conformità normativa non sono optional. Più i dati trattati sono sensibili, maggiore è l&#8217;impegno richiesto.</li>



<li>Scalabilità cloud: dimensionare l&#8217;infrastruttura in modo che possa crescere insieme all&#8217;azienda evita costi eccessivi all&#8217;inizio e blocchi in futuro.</li>
</ul>



<p class="wp-block-paragraph">Il modo più efficace per contenere il budget è partire dalle funzionalità essenziali. Poi, si prevede una crescita graduale, invece di costruire tutto subito. Su questo approccio si basa il nostro servizio di <a href="https://renor.it/servizi/sviluppo-e-cloud/">sviluppo e cloud</a>: realizziamo l&#8217;applicazione e la ospitiamo su un&#8217;infrastruttura pensata per adattarsi alle reali esigenze. Così i costi seguono la crescita effettiva dell&#8217;utilizzo, anziché ipotesi sovradimensionate.</p>



<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow">
<p class="wp-block-paragraph">Ogni euro di un preventivo racconta una scelta: la trasparenza sta nel sapere quale funzione, quale integrazione o quale livello di sicurezza lo giustifica.</p>
</blockquote>



<h2 id="h-come-leggere-e-confrontare-un-preventivo-software-senza-farsi-ingannare" class="wp-block-heading">Come leggere e confrontare un preventivo software, senza farsi ingannare</h2>



<p class="wp-block-paragraph">Due preventivi con la stessa cifra finale possono nascondere realtà molto diverse. Infatti, la differenza non sta nel numero in fondo alla pagina, ma nel dettaglio delle voci. Cosa è incluso, cosa verrà fatturato a parte e cosa manca del tutto: ecco cosa conta davvero. Imparare a leggere un preventivo con occhio critico è quindi il modo migliore per evitare sorprese a metà progetto o costi che ricompaiono dopo il rilascio.</p>



<p class="wp-block-paragraph">Il primo elemento da verificare è come vengono espresse le ore/uomo. Un preventivo serio distingue le attività per fase, come analisi, sviluppo, test e rilascio. Inoltre, associa a ciascuna fase una stima realistica. Diffidate, quindi, delle cifre tonde e indistinte. Se non è chiaro quante ore servono e per fare cosa, non avete uno strumento per capire dove finiscono i vostri soldi. Chiedete sempre cosa succede se una fase richiede più tempo del previsto e chi si assume quel rischio.</p>



<p class="wp-block-paragraph">Le voci che più spesso vengono trascurate sono quelle successive al rilascio. Infatti, un&#8217;applicazione non finisce il giorno in cui va online. Va mantenuta, aggiornata e supportata nel tempo. Quando confrontate più offerte, controllate quindi che questi aspetti siano dichiarati esplicitamente.</p>



<ul class="wp-block-list">
<li>Manutenzione: correzione di errori, aggiornamenti di sicurezza e adeguamenti tecnici. Va chiarito se è inclusa per un periodo o fatturata a canone.</li>



<li>Hosting: dove vive l&#8217;applicazione, con quali garanzie di disponibilità e chi ne gestisce i costi mensili.</li>



<li>Assistenza post-rilascio: tempi di risposta, modalità di contatto ed eventuali ore già comprese nel prezzo.</li>



<li>Proprietà del codice: verificate che il software sviluppato resti di vostra proprietà, senza vincoli nascosti.</li>
</ul>



<p class="wp-block-paragraph">Un buon partner tecnologico non teme la trasparenza. Mette per iscritto ciò che è incluso e ciò che non lo è. Inoltre, spiega le scelte tecniche in un linguaggio comprensibile e vi mette nelle condizioni di decidere con consapevolezza. Con i nostri servizi di Sviluppo e cloud lavoriamo proprio in questa direzione: preventivi leggibili, voci dettagliate e continuità nella gestione tra applicazione e infrastruttura. Così saprete sempre cosa state pagando e perché.</p>



<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow">
<p class="wp-block-paragraph">Un preventivo chiaro non è quello che costa meno, ma quello che vi permette di sapere in anticipo cosa otterrete e a quali condizioni.</p>
</blockquote>



<h2 id="h-sviluppo-su-misura-o-soluzioni-pronte-quale-conviene-alla-tua-azienda" class="wp-block-heading">Sviluppo su misura o soluzioni pronte: quale conviene alla tua azienda</h2>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="800" height="800" src="https://renor.it/wp-content/uploads/2026/07/preventivo-per-lo-sviluppo-di-unapplicazione-web-aziendale-guida-completa-ai-costi-fig-1-800x800.png" alt="Team di sviluppatori al lavoro su un'applicazione web aziendale" class="wp-image-3018" srcset="https://renor.it/wp-content/uploads/2026/07/preventivo-per-lo-sviluppo-di-unapplicazione-web-aziendale-guida-completa-ai-costi-fig-1-800x800.png 800w, https://renor.it/wp-content/uploads/2026/07/preventivo-per-lo-sviluppo-di-unapplicazione-web-aziendale-guida-completa-ai-costi-fig-1-150x150.png 150w, https://renor.it/wp-content/uploads/2026/07/preventivo-per-lo-sviluppo-di-unapplicazione-web-aziendale-guida-completa-ai-costi-fig-1-300x300.png 300w" sizes="auto, (max-width: 800px) 100vw, 800px" /></figure>



<p class="wp-block-paragraph">Prima ancora di valutare un preventivo sviluppo applicazione web aziendale, molte aziende si trovano davanti a una scelta di fondo. Da un lato c&#8217;è l&#8217;idea di adottare un software già pronto, spesso in abbonamento. Dall&#8217;altro, quella di investire in un&#8217;applicazione sviluppata su misura. Non esiste una risposta valida per tutti: la decisione giusta dipende da quanto i tuoi processi sono standard o specifici. Dipende anche dai volumi di lavoro e da quanto quel software incide sul cuore del tuo business.</p>



<p class="wp-block-paragraph">Le soluzioni pronte hanno vantaggi concreti: costo iniziale contenuto, tempi di attivazione rapidi e manutenzione a carico del fornitore. Sono la scelta sensata quando le tue esigenze coincidono con ciò che il mercato già offre. Ad esempio, per la gestione documentale di base, la posta o la contabilità standard.</p>



<p class="wp-block-paragraph">Lo sviluppo su misura entra in gioco quando il software preconfezionato ti costringe a piegare i tuoi processi allo strumento, invece del contrario. I segnali tipici sono questi:</p>



<ul class="wp-block-list">
<li>Usi diversi gestionali che non dialogano tra loro e obbligano a doppie digitazioni.</li>



<li>Paghi licenze per decine di utenti ma sfrutti solo una piccola parte delle funzioni.</li>



<li>I tuoi processi rappresentano un vantaggio competitivo e non vuoi appiattirli su uno standard.</li>



<li>Prevedi crescita o cambiamenti frequenti che un software rigido non riesce a seguire.</li>
</ul>



<p class="wp-block-paragraph">Il confronto corretto, dunque, non riguarda il prezzo d&#8217;acquisto, ma il ritorno nel tempo. Un abbonamento a basso costo può diventare oneroso man mano che aumentano utenti, integrazioni e personalizzazioni forzate. Un&#8217;applicazione su misura richiede un investimento iniziale maggiore, ma elimina lavoro manuale e riduce gli errori. Inoltre, resta di tua proprietà e si adatta alla tua azienda, invece del contrario.</p>



<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow">
<p class="wp-block-paragraph">La domanda giusta non è &#8220;quanto costa oggi&#8221;, ma &#8220;quanto mi farà risparmiare o guadagnare nei prossimi tre anni&#8221;.</p>
</blockquote>



<p class="wp-block-paragraph">Nella pratica, la soluzione migliore è spesso ibrida. Si tratta di uno sviluppo mirato dove serve differenziarsi ed efficienza, poggiato su un&#8217;infrastruttura cloud che garantisce scalabilità e continuità. È esattamente l&#8217;ambito in cui interveniamo con i nostri servizi di sviluppo e cloud. Prima di parlare di costi, infatti, vale la pena analizzare insieme i tuoi processi per capire dove il custom conviene davvero e dove no.</p>



<h2 id="h-dalla-richiesta-al-rilascio-come-lavoriamo-su-un-progetto-web" class="wp-block-heading">Dalla richiesta al rilascio: come lavoriamo su un progetto web</h2>



<p class="wp-block-paragraph">Un preventivo affidabile nasce sempre da un metodo di lavoro chiaro. Sapere in anticipo quali sono le fasi di un progetto ti aiuta a capire dove vanno le risorse. Ti aiuta anche a capire quando prendere le decisioni importanti e quali risultati aspettarti a ogni passaggio. Ecco, quindi, come strutturiamo tipicamente lo sviluppo di un&#8217;applicazione web aziendale.</p>



<h2 id="h-le-fasi-principali-di-un-progetto" class="wp-block-heading">Le fasi principali di un progetto</h2>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="800" height="800" src="https://renor.it/wp-content/uploads/2026/07/preventivo-per-lo-sviluppo-di-unapplicazione-web-aziendale-guida-completa-ai-costi-fig-2-800x800.png" alt="Imprenditore e consulente esaminano un preventivo software" class="wp-image-3019" srcset="https://renor.it/wp-content/uploads/2026/07/preventivo-per-lo-sviluppo-di-unapplicazione-web-aziendale-guida-completa-ai-costi-fig-2-800x800.png 800w, https://renor.it/wp-content/uploads/2026/07/preventivo-per-lo-sviluppo-di-unapplicazione-web-aziendale-guida-completa-ai-costi-fig-2-150x150.png 150w, https://renor.it/wp-content/uploads/2026/07/preventivo-per-lo-sviluppo-di-unapplicazione-web-aziendale-guida-completa-ai-costi-fig-2-300x300.png 300w" sizes="auto, (max-width: 800px) 100vw, 800px" /></figure>



<ul class="wp-block-list">
<li>Analisi e raccolta dei requisiti: partiamo dai tuoi processi reali, non da ipotesi. Definiamo obiettivi, utenti coinvolti e priorità, così da tradurre le esigenze del business in specifiche concrete.</li>



<li>Prototipo: prima di scrivere il codice definitivo, costruiamo una versione navigabile dell&#8217;applicazione. Ti permette di vedere e provare le schermate, correggere la rotta presto ed evitare costi di rilavorazione più avanti.</li>



<li>Sviluppo: realizziamo l&#8217;applicazione in modo incrementale, con rilasci intermedi da verificare insieme. In questo modo il progetto resta sotto controllo e le sorprese si riducono al minimo.</li>



<li>Cloud e messa in produzione: predisponiamo l&#8217;ambiente in cui l&#8217;applicazione sarà eseguita, curando affidabilità e accessibilità per i tuoi utenti.</li>



<li>Rilascio e assistenza: accompagniamo l&#8217;avvio in uso reale e restiamo un punto di riferimento per correzioni, miglioramenti ed evoluzioni future.</li>
</ul>



<p class="wp-block-paragraph">Questo percorso è il cuore del nostro servizio di Sviluppo e cloud: progettiamo, realizziamo e portiamo online applicazioni web pensate sulle reali esigenze dell&#8217;azienda. Lavorare per fasi, quindi, non è una formalità. È il modo più efficace per tenere insieme tempi, budget e qualità del risultato.</p>



<p class="wp-block-paragraph">Non sempre, però, il punto di partenza è già chiaro. Molte aziende sanno di avere un problema da risolvere, ma non ancora quale sia la soluzione giusta. In questi casi, la fase di analisi può essere anticipata da un percorso di <a href="https://renor.it/servizi/consulenza-it/">Consulenza IT</a>. Questo è utile per mettere a fuoco obiettivi e priorità prima ancora di parlare di preventivo. Definire bene la direzione all&#8217;inizio, infatti, è il modo migliore per ottenere una stima realistica e un progetto che porta valore concreto.</p>



<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow">
<p class="wp-block-paragraph">Un metodo trasparente, con fasi verificabili e rilasci progressivi, è la prima garanzia di un preventivo che rispetta ciò che promette.</p>
</blockquote>



<h2 id="h-richiedi-un-preventivo-su-misura-per-lo-sviluppo-della-tua-applicazione-web-aziendale" class="wp-block-heading">Richiedi un preventivo su misura per lo sviluppo della tua applicazione web aziendale</h2>



<p class="wp-block-paragraph">Arrivati a questo punto, hai gli strumenti per capire cosa determina il costo di un&#8217;applicazione web. Sai anche come valutare un&#8217;offerta e quale approccio si adatta meglio alla tua realtà. Il passo successivo, quindi, è tradurre queste consapevolezze in un progetto concreto, calibrato sulle esigenze reali della tua azienda.</p>



<p class="wp-block-paragraph">Ogni preventivo serio parte da una domanda semplice: qual è il problema che vuoi risolvere? Non esiste un prezzo standard, perché non esistono due aziende identiche. Per questo motivo, il nostro primo passo non è un listino, ma un confronto diretto. In questo confronto analizziamo obiettivi, processi da digitalizzare e priorità di budget.</p>



<p class="wp-block-paragraph">Durante una prima <a href="https://renor.it/servizi/consulenza-strategica/">consulenza strategica</a>, senza impegno, mettiamo a fuoco insieme gli elementi che contano davvero:</p>



<ul class="wp-block-list">
<li>Gli obiettivi di business che l&#8217;applicazione deve supportare e i risultati attesi</li>



<li>Le funzionalità essenziali da rilasciare subito e quelle rimandabili a fasi successive</li>



<li>Il perimetro tecnico del progetto, con la nostra attività di sviluppo e cloud a coprire realizzazione e messa in esercizio</li>



<li>Una stima di costi e tempi chiara, articolata per fasi e priorità</li>
</ul>



<p class="wp-block-paragraph">Questo approccio ti permette di ricevere un preventivo sviluppo applicazione web aziendale realmente trasparente, dove ogni voce corrisponde a un valore concreto e non a una cifra generica. Sai in anticipo cosa stai pagando, perché e quali benefici ti aspetti di ottenere.</p>



<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow">
<p class="wp-block-paragraph">Un buon preventivo non è quello con il prezzo più basso, ma quello che descrive con precisione ciò che riceverai e come contribuirà agli obiettivi della tua impresa.</p>
</blockquote>



<p class="wp-block-paragraph">Se hai un&#8217;idea da valutare o un progetto già definito da mettere a terra, contatta RENOR per una consulenza dedicata. Analizzeremo la tua richiesta e ti forniremo un preventivo personalizzato, costruito sulle tue reali necessità e non su un pacchetto preconfezionato. È il modo più semplice, infatti, per passare dalla teoria dei costi a una proposta concreta e misurabile.</p>



<div class="wp-block-group scriba-cta"><div class="wp-block-group__inner-container is-layout-flow wp-block-group-is-layout-flow"><p><strong>Ti serve un supporto concreto?</strong> Scopri il nostro servizio <a href="https://renor.it/servizi/sviluppo-e-cloud/">Sviluppo e cloud</a> oppure <a href="https://renor.it/contatti/">contattaci</a> per una consulenza.</p></div></div>
<p>L'articolo <a href="https://renor.it/blog/sviluppo-software-programmazione/preventivo-sviluppo-applicazione-web-aziendale/">Preventivo per lo sviluppo di un&#8217;applicazione web aziendale: guida completa ai costi</a> proviene da <a href="https://renor.it">RENOR &amp; Partners S.r.l.</a>.</p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>AI per la scrittura di articoli: scrivere senza delegare il pensiero</title>
		<link>https://renor.it/blog/sviluppo-software-programmazione/ai-per-la-scrittura-di-articoli/</link>
		
		<dc:creator><![CDATA[Simone Renzi]]></dc:creator>
		<pubDate>Mon, 29 Dec 2025 01:10:36 +0000</pubDate>
				<category><![CDATA[Sviluppo Software & Programmazione]]></category>
		<category><![CDATA[ai writing]]></category>
		<category><![CDATA[content marketing]]></category>
		<category><![CDATA[intelligenza artificiale]]></category>
		<category><![CDATA[scrittura assistita]]></category>
		<category><![CDATA[seo editoriale]]></category>
		<category><![CDATA[wordpress]]></category>
		<category><![CDATA[writerflow]]></category>
		<guid isPermaLink="false">https://renor.it/?p=2852</guid>

					<description><![CDATA[<p>Con la creazione dell&#8217;infrastruttura di RunAI in RENOR &#38; Partners, abbiamo sviluppato un plugin WordPress che aiuta gli autori ad aumentare la visibilità online pubblicando contenuti di qualità: WriterFlow.WriterFlow nasce proprio per un uso consapevole dell’AI per la scrittura di articoli, come supporto al pensiero umano e non come sua sostituzione. Chi si affida a [&#8230;]</p>
<p>L'articolo <a href="https://renor.it/blog/sviluppo-software-programmazione/ai-per-la-scrittura-di-articoli/">AI per la scrittura di articoli: scrivere senza delegare il pensiero</a> proviene da <a href="https://renor.it">RENOR &amp; Partners S.r.l.</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p class="wp-block-paragraph">Con la creazione dell&#8217;infrastruttura di <strong><a href="https://runai.it">RunAI</a> </strong>in RENOR &amp; Partners, abbiamo sviluppato un plugin WordPress che aiuta gli autori ad aumentare la visibilità online pubblicando contenuti di qualità: <strong><a href="https://runai.it/writerflow">WriterFlow</a></strong>.<br>WriterFlow nasce proprio per un uso consapevole dell’AI per la scrittura di articoli, come supporto al pensiero umano e non come sua sostituzione.</p>



<p class="wp-block-paragraph">Chi si affida a ChatGPT per la creazione automatica di contenuti rischia di rimanere indietro. La SEO richiede strategie complesse e non basta fare un copia e incolla, necessita di creatività e di contenuti pensati e scritti per il lettore. Gli articoli scritti interamente da ChatGPT presentano sempre queste caratteristiche:</p>



<ul class="wp-block-list">
<li>Sono in linea con la media</li>



<li>Non introducono esperienza reale</li>



<li>Non risolvono un problema meglio di altri</li>



<li>Sono facilmente riconoscibili anche senza l&#8217;utilizzo di un detector AI</li>



<li>Non tengono conto delle esigenze dell&#8217;utente.</li>
</ul>



<p class="wp-block-paragraph">Proprio sull&#8217;ultimo punto vale la pena soffermarci per un secondo. </p>



<h2 class="wp-block-heading" id="h-ai-per-la-scrittura-di-articoli-scrivere-pensando-alle-persone-non-alla-seo">AI per la scrittura di articoli: scrivere pensando alle persone, non alla SEO</h2>



<p class="wp-block-paragraph">Ti sembrerà assurdo ma gli algoritmi dei motori di ricerca tendono a preferire contenuti originali e di valore che risultino utili e interessanti per l&#8217;utente finale. Questo è ciò che posiziona meglio un sito web o un articolo nei risultati di ricerca. Abbiamo affrontato questo argomento anche in questo articolo: <a href="https://renor.it/blog/marketing-business-digitale/come-scrivere-un-articolo-di-blog/">come scrivere un articolo di blog</a>. </p>



<h2 class="wp-block-heading" id="h-writerflow-e-l-ai-per-la-scrittura-di-articoli-non-si-sostituiscono-all-umano">WriterFlow e l’AI per la scrittura di articoli non si sostituiscono all’umano</h2>



<p class="wp-block-paragraph">Il plugin si avvale di un’intelligenza artificiale dedicata alla SEO, pensata come AI per la scrittura di articoli, capace di generare contenuti ottimizzati in base al ragionamento dell&#8217;utente, fornendo opzioni diverse, sinonimi e suggerimenti per migliorare la qualità della scrittura, rimanendo un semplice supporto alla stesura dell&#8217;idea e non sostituendosi all&#8217;autore.</p>



<p class="wp-block-paragraph">Ad esempio potrei scrivere:<br><em>&#8220;WriterFlow è un plugin AI per WordPress che ti dà una mano a scrivere gli articoli&#8221;</em></p>



<p class="wp-block-paragraph">Richiedendo un&#8217;alternativa, quello che ottengo grazie a WriterFlow è questo:</p>



<p class="wp-block-paragraph">&#8220;<em>WriterFlow è un plugin per WordPress che utilizza l&#8217;intelligenza artificiale per supportare gli autori nella scrittura di articoli.<em>&#8220;</em></em></p>



<h2 class="wp-block-heading" id="h-ai-per-la-scrittura-di-articoli-e-selezione-di-titoli-efficaci">AI per la scrittura di articoli e selezione di titoli efficaci</h2>



<figure class="wp-block-image size-large"><img decoding="async" src="https://renor.it/wp-content/uploads/2025/12/Screenshot-2025-12-29-alle-01.12.53.png" alt="AI per la scrittura di articoli con WriterFlow: suggerimenti automatici di titoli in WordPress" class="wp-image-2855"/><figcaption class="wp-element-caption">WriterFlow propone automaticamente idee per titoli in linea con categoria e argomento dell’articolo.</figcaption></figure>



<p class="wp-block-paragraph">Per far crescere il proprio sito è indispensabile nutrirlo continuamente di nuovi contenuti. Google non fornisce un numero esatto di articoli da pubblicare ogni giorno, non c&#8217;è un vademecum ma è possibile affermare con buona probabilità che la frequenza di pubblicazione dipenda fortemente dal tipo di sito web. </p>



<p class="wp-block-paragraph">Un piccolo/medio blog dovrebbe pubblicare non più di 2/3 articoli a settimana, un sito di News è chiaro che ne debba pubblicare molti di più. Ma per un blog aziendale o per un blog personale le idee si esauriscono velocemente. </p>



<p class="wp-block-paragraph">Con WriterFlow trovare il titolo perfetto è facile. Basta specificare categoria e tag, poi lasciare che WriterFlow generi 10 idee per titoli in linea con l&#8217;argomento selezionato.</p>



<p class="wp-block-paragraph">Tanto tempo risparmiato e contenuti sempre di qualità.</p>



<h2 class="wp-block-heading" id="h-dalla-scelta-all-azione">Dalla scelta all&#8217;azione</h2>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1416" height="780" src="https://renor.it/wp-content/uploads/2025/12/Screenshot-2025-12-29-alle-01.32.57.png" alt="AI per la scrittura di articoli con WriterFlow: inserimento automatico del titolo in WordPress" class="wp-image-2858" srcset="https://renor.it/wp-content/uploads/2025/12/Screenshot-2025-12-29-alle-01.32.57.png 1416w, https://renor.it/wp-content/uploads/2025/12/Screenshot-2025-12-29-alle-01.32.57-300x165.png 300w, https://renor.it/wp-content/uploads/2025/12/Screenshot-2025-12-29-alle-01.32.57-768x423.png 768w" sizes="auto, (max-width: 1416px) 100vw, 1416px" /><figcaption class="wp-element-caption">Con un solo click, WriterFlow inserisce il titolo scelto direttamente nell’editor WordPress.</figcaption></figure>



<p class="wp-block-paragraph">Basta un click sul titolo prescelto e viene automaticamente inserito. WriterFlow si integra perfettamente con il tuo workflow WordPress, semplificando la creazione di contenuti ottimizzati per la SEO.</p>



<p class="wp-block-paragraph">Basta perdere tempo con la ricerca del titolo perfetto. È sufficiente fornire l&#8217;argomento e WriterFlow proporrà diverse opzioni. Se non trovate quello che cercate, basta cliccare un tasto per rigenerare nuove idee.</p>



<h2 class="wp-block-heading" id="h-scrittura-assistita-un-uso-consapevole-dell-ai-per-la-scrittura-di-articoli">Scrittura assistita: un uso consapevole dell’AI per la scrittura di articoli</h2>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1414" height="632" src="https://renor.it/wp-content/uploads/2025/12/Screenshot-2025-12-29-alle-01.37.11.png" alt="AI per la scrittura di articoli con WriterFlow: suggerimenti di testo durante la scrittura" class="wp-image-2859" srcset="https://renor.it/wp-content/uploads/2025/12/Screenshot-2025-12-29-alle-01.37.11.png 1414w, https://renor.it/wp-content/uploads/2025/12/Screenshot-2025-12-29-alle-01.37.11-300x134.png 300w, https://renor.it/wp-content/uploads/2025/12/Screenshot-2025-12-29-alle-01.37.11-768x343.png 768w" sizes="auto, (max-width: 1414px) 100vw, 1414px" /><figcaption class="wp-element-caption">WriterFlow propone suggerimenti di testo mentre scrivi, lasciando all’autore la libertà di accettarli o modificarli.</figcaption></figure>



<p class="wp-block-paragraph">Nei suggerimenti di testo hai due modalità. Questo approccio rende l’AI per la scrittura di articoli uno strumento discreto e realmente utile. Accettare il testo proposto, oppure iniziare a scrivere per poi variare il contenuto con nuove idee che ti vengono in mente. </p>



<h3 class="wp-block-heading" id="h-accettazione-del-testo-proposto">Accettazione del testo proposto</h3>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1388" height="676" src="https://renor.it/wp-content/uploads/2025/12/Screenshot-2025-12-29-alle-01.42.23.png" alt="AI per la scrittura di articoli con WriterFlow: inserimento del testo suggerito nei blocchi Gutenberg" class="wp-image-2861" srcset="https://renor.it/wp-content/uploads/2025/12/Screenshot-2025-12-29-alle-01.42.23.png 1388w, https://renor.it/wp-content/uploads/2025/12/Screenshot-2025-12-29-alle-01.42.23-300x146.png 300w, https://renor.it/wp-content/uploads/2025/12/Screenshot-2025-12-29-alle-01.42.23-768x374.png 768w" sizes="auto, (max-width: 1388px) 100vw, 1388px" /><figcaption class="wp-element-caption">Nei blocchi di paragrafo è possibile inserire il suggerimento di testo con un click o premendo TAB.</figcaption></figure>



<p class="wp-block-paragraph">Nei blocchi di paragrafo di Gutenberg ti basta cliccare sul suggerimento per inserire tutta la frase suggerita. Oppure premere semplicemente il tasto &#8220;TAB&#8221;. </p>



<h2 class="wp-block-heading" id="h-frasi-alternative">Frasi alternative</h2>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1396" height="766" src="https://renor.it/wp-content/uploads/2025/12/Screenshot-2025-12-29-alle-01.44.49.png" alt="AI per la scrittura di articoli con WriterFlow: riformulazione di una frase selezionata" class="wp-image-2862" style="aspect-ratio:1.8224964404366397" srcset="https://renor.it/wp-content/uploads/2025/12/Screenshot-2025-12-29-alle-01.44.49.png 1396w, https://renor.it/wp-content/uploads/2025/12/Screenshot-2025-12-29-alle-01.44.49-300x165.png 300w, https://renor.it/wp-content/uploads/2025/12/Screenshot-2025-12-29-alle-01.44.49-768x421.png 768w" sizes="auto, (max-width: 1396px) 100vw, 1396px" /><figcaption class="wp-element-caption">Selezionando una frase, WriterFlow genera alternative più coerenti e professionali.</figcaption></figure>



<p class="wp-block-paragraph">Non sei soddisfatto di come hai scritto una frase e la vorresti riformulata in modo più professionale e aderente al resto dell&#8217;articolo? Nulla di più semplice. <br>Con WriterFlow attivo è sufficiente selezionare la frase che vuoi riformulare e verranno generate immediatamente delle alternative. Ti basta premere l&#8217;alternativa che preferisci oppure generare nuove alternative se quelle proposte non ti soddisfano. </p>



<h2 class="wp-block-heading" id="h-scegli-la-parola-perfetta">Scegli la parola perfetta</h2>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1418" height="800" src="https://renor.it/wp-content/uploads/2025/12/Screenshot-2025-12-29-alle-01.47.20.png" alt="AI per la scrittura di articoli con WriterFlow: suggerimento di sinonimi durante la revisione del testo" class="wp-image-2863" srcset="https://renor.it/wp-content/uploads/2025/12/Screenshot-2025-12-29-alle-01.47.20.png 1418w, https://renor.it/wp-content/uploads/2025/12/Screenshot-2025-12-29-alle-01.47.20-300x169.png 300w, https://renor.it/wp-content/uploads/2025/12/Screenshot-2025-12-29-alle-01.47.20-768x433.png 768w" sizes="auto, (max-width: 1418px) 100vw, 1418px" /><figcaption class="wp-element-caption">Selezionando una parola, WriterFlow propone sinonimi alternativi per migliorare precisione e stile del testo.</figcaption></figure>



<p class="wp-block-paragraph">Stai cercando un sinonimo che non ti viene? WriterFlow ti velocizza anche in questo, mostrando il lato più pratico dell’AI per la scrittura di articoli. Fai doppio click sulla parola di cui vuoi cercare un sinonimo in modo che sia evidenziata e ti verranno consigliati 5 sinonimi. Se i sinonimi proposti non ti convincono, puoi cliccare su &#8220;rigenera&#8221; per ottenere 5 nuove opzioni.  Scegli il sinonimo che preferisci e verrà inserito al posto della parola originale.</p>



<h2 class="wp-block-heading" id="h-modalita-automatica-o-manuale">Modalità automatica o manuale?</h2>



<h3 class="wp-block-heading" id="h-in-modalita-automatica-puoi-impostare-un-tempo-di-inattivita-per-ricevere-suggerimenti">In modalità automatica puoi impostare un tempo di inattività per ricevere suggerimenti</h3>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1424" height="786" src="https://renor.it/wp-content/uploads/2025/12/Screenshot-2025-12-29-alle-01.50.28.png" alt="AI per la scrittura di articoli con WriterFlow: impostazioni della modalità automatica dei suggerimenti" class="wp-image-2864" srcset="https://renor.it/wp-content/uploads/2025/12/Screenshot-2025-12-29-alle-01.50.28.png 1424w, https://renor.it/wp-content/uploads/2025/12/Screenshot-2025-12-29-alle-01.50.28-300x166.png 300w, https://renor.it/wp-content/uploads/2025/12/Screenshot-2025-12-29-alle-01.50.28-768x424.png 768w" sizes="auto, (max-width: 1424px) 100vw, 1424px" /><figcaption class="wp-element-caption">La modalità automatica consente di ricevere suggerimenti dopo un periodo di inattività configurabile.</figcaption></figure>



<p class="wp-block-paragraph">La modalità automatica è molto comoda quando si vuole ricevere il suggerimento dopo un certo periodo di inattività. La durata del tempo di inattività è configurabile tramite le impostazioni di WriterFlow.</p>



<p class="wp-block-paragraph">Con un tempo di 5 secondi, come illustrato nell&#8217;esempio, il suggerimento si attiverà dopo 5 secondi di stop alla scrittura.</p>



<h3 class="wp-block-heading" id="h-in-modalita-manuale-sei-tu-a-scegliere-quando-vuoi-ricevere-un-suggerimento">In modalità manuale sei tu a scegliere quando vuoi ricevere un suggerimento</h3>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1254" height="270" src="https://renor.it/wp-content/uploads/2025/12/Screenshot-2025-12-29-alle-01.54.52.png" alt="Pulsante Suggerisci nella modalità manuale" class="wp-image-2865" srcset="https://renor.it/wp-content/uploads/2025/12/Screenshot-2025-12-29-alle-01.54.52.png 1254w, https://renor.it/wp-content/uploads/2025/12/Screenshot-2025-12-29-alle-01.54.52-300x65.png 300w, https://renor.it/wp-content/uploads/2025/12/Screenshot-2025-12-29-alle-01.54.52-768x165.png 768w" sizes="auto, (max-width: 1254px) 100vw, 1254px" /><figcaption class="wp-element-caption">In modalità manuale, il pulsante “Suggerisci” compare accanto al cursore dopo alcuni secondi di inattività.</figcaption></figure>



<p class="wp-block-paragraph">Nella modalità manuale, dopo tre secondi di stop alla scrittura comparirà il tasto suggerisci a destra del cursore. Ti basterà cliccare sul pulsante per ricevere i suggerimenti di scrittura. Nella modalità manuale, le funzioni di generazione alternative e di suggerimento sinonimico saranno ancora disponibili. Come nel caso della modalità automatica dovrai solamente selezionare la frase o la parola per ottenere rispettivamente il testo alternativo o il sinonimo desiderato.</p>



<h1 class="wp-block-heading" id="h-con-writerflow-paghi-solo-quello-che-usi">Con WriterFlow paghi solo quello che usi</h1>



<div class="wp-block-media-text is-stacked-on-mobile"><figure class="wp-block-media-text__media"><img loading="lazy" decoding="async" width="478" height="422" src="https://renor.it/wp-content/uploads/2025/12/Screenshot-2025-12-29-alle-01.58.40.png" alt="Visualizzazione del credito residuo nell’editor WordPress" class="wp-image-2866 size-full" srcset="https://renor.it/wp-content/uploads/2025/12/Screenshot-2025-12-29-alle-01.58.40.png 478w, https://renor.it/wp-content/uploads/2025/12/Screenshot-2025-12-29-alle-01.58.40-300x265.png 300w" sizes="auto, (max-width: 478px) 100vw, 478px" /></figure><div class="wp-block-media-text__content">
<p class="wp-block-paragraph">Nel menu a destra dell&#8217;editor dell&#8217;articolo hai sempre modo di controllare il credito residuo. Ad ogni interazione il credito verrà aggiornato in modo automatico. Niente sorprese. </p>



<p class="wp-block-paragraph">Inoltre i nuovi iscritti possono godere di un credito gratuito di 5 euro per testare le funzionalità di WriterFlow. I 5 euro di credito ti basteranno per almeno 15 articoli di media lunghezza. </p>
</div></div>



<p class="wp-block-paragraph">Iscrizione e ricarica sono operazioni semplicissime. La registrazione e la creazione di una chiave API sono operazioni che avvengono in modo automatico direttamente dalla tua area amministrativa di WordPress. La ricarica richiede invece l&#8217;accesso al portale di RunAI e potrai ricaricare il tuo credito con un minimo di 5 euro. </p>



<p class="wp-block-paragraph">RunAI utilizza transazioni sicure tramite l&#8217;introduzione dei gateway di pagamento PayPal e Stripe. È necessaria una carta di credito. Non ci sono costi ricorrenti, non ci sono piani in abbonamento. Ricarichi il tuo credito e utilizzi WriterFlow. Nulla di più semplice. </p>



<p class="wp-block-paragraph">Puoi usare lo stesso account WriterFlow anche su più siti WordPress e il credito non ha scadenza. Se un mese sei in ferie e non stai lavorando non dovrai continuare a pagare per un servizio che non utilizzi. I costi sono puramente a consumo. </p>



<h2 class="wp-block-heading" id="h-privacy-e-data-retention">Privacy e data retention</h2>



<p class="wp-block-paragraph">La privacy è garantita da <a href="https://runai.it">RunAI</a>, la nostra piattaforma di intelligenza artificiale con nodi di inferenza Apple Silicon criptati end-to-end. Nessun contenuto viene salvato, i dati vengono elaborati solo durante l&#8217;utilizzo del servizio e cancellati un microsecondo dopo averti fornito il suggerimento nel rispetto delle normative GDPR in modo trasparente e sicuro per gli utenti. </p>



<h2 class="wp-block-heading" id="h-conclusione">Conclusione</h2>



<p class="wp-block-paragraph">WriterFlow è lo strumento innovativo che rivoluziona il modo di scrivere online, offrendo un uso consapevole dell’AI per la scrittura di articoli.</p>



<p class="wp-block-paragraph">Scarica WriterFlow e inizia ad usarlo con il credito gratuito. Diventerà il tuo compagno di scrittura e ti aiuterà a creare contenuti di qualità.</p>
<p>L'articolo <a href="https://renor.it/blog/sviluppo-software-programmazione/ai-per-la-scrittura-di-articoli/">AI per la scrittura di articoli: scrivere senza delegare il pensiero</a> proviene da <a href="https://renor.it">RENOR &amp; Partners S.r.l.</a>.</p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Da Zero a Packagist: pubblicare una libreria PHP su Composer</title>
		<link>https://renor.it/blog/sviluppo-software-programmazione/da-zero-a-packagist-pubblicare-una-libreria-php-su-composer/</link>
		
		<dc:creator><![CDATA[Simone Renzi]]></dc:creator>
		<pubDate>Mon, 12 May 2025 22:06:01 +0000</pubDate>
				<category><![CDATA[Sviluppo Software & Programmazione]]></category>
		<category><![CDATA[CI/CD]]></category>
		<category><![CDATA[Composer]]></category>
		<category><![CDATA[dependency management]]></category>
		<category><![CDATA[GitHub]]></category>
		<category><![CDATA[open-source]]></category>
		<category><![CDATA[package publishing]]></category>
		<category><![CDATA[Packagist]]></category>
		<category><![CDATA[php]]></category>
		<category><![CDATA[PHP library]]></category>
		<category><![CDATA[PHPUnit]]></category>
		<category><![CDATA[PSR-4]]></category>
		<category><![CDATA[release workflow]]></category>
		<category><![CDATA[semantic versioning]]></category>
		<guid isPermaLink="false">https://renor.it/?p=490</guid>

					<description><![CDATA[<p>Pubblicare un pacchetto Composer significa rendere il proprio codice installabile con un semplice comando da CLI composer require vendor/package e tenere aggiornamenti, versioni e dipendenze sotto controllo. Per seguire la guida abbiamo bisogno di: Rifacendoci all&#8217;articolo in cui avevamo visto come sviluppare una libreria di Statistica descrittiva la struttura della repository era la seguente: Nel [&#8230;]</p>
<p>L'articolo <a href="https://renor.it/blog/sviluppo-software-programmazione/da-zero-a-packagist-pubblicare-una-libreria-php-su-composer/">Da Zero a Packagist: pubblicare una libreria PHP su Composer</a> proviene da <a href="https://renor.it">RENOR &amp; Partners S.r.l.</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p class="wp-block-paragraph">Pubblicare un pacchetto Composer significa rendere il proprio codice installabile con un semplice comando da CLI</p>



<p class="wp-block-paragraph"><code>composer require vendor/package</code></p>



<p class="wp-block-paragraph">e tenere aggiornamenti, versioni e dipendenze sotto controllo. Per seguire la guida  abbiamo bisogno di: </p>



<ul class="wp-block-list">
<li>Git versione maggiore o uguale alla 2.0 installata e configurata</li>



<li>Un account GitHub e token con permesso repo</li>



<li>Composer con versione maggiore o uguale alla 2.5 in <code>$PATH</code></li>



<li>Account gratuito su Packagist.org (che si registra tramite GitHub via OAuth)</li>
</ul>



<p class="wp-block-paragraph">Rifacendoci all&#8217;articolo in cui avevamo visto come sviluppare una libreria di <a href="https://renor.it/una-classe-di-statistica-descrittiva-in-php/" data-type="link" data-id="https://renor.it/una-classe-di-statistica-descrittiva-in-php/">Statistica descrittiva</a> la struttura della repository era la seguente:</p>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#1E1E1E"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" data-code="descriptive-statistics-php/
├─ composer.json
├─ composer.lock
├─ phpunit.xml
├─ examples/
│  └─ geometric_mean_demo.php
│  └─ harmonic_mean_demo.php
│  └─ iqr_demo.php
│  └─ mad_demo.php
│  └─ mean_demo.php
│  └─ median_demo.php
│  └─ min_max_demo.php
│  └─ mode_demo.php
│  └─ percentile_demo.php
│  └─ range_demo.php
│  └─ standard_deviation_demo.php
│  └─ trimmed_mean_demo.php
│  └─ variance_demo.php
├─ src/
│  └─ DescriptiveStats.php
├─ tests/
│  └─ DescriptiveStatsTest.php
└─ vendor/
    └─ autoload.php" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"><span style="color: #D4D4D4">descriptive-statistics-php/</span></span>
<span class="line"><span style="color: #D4D4D4">├─ composer</span><span style="color: #D4D4D4">.</span><span style="color: #D4D4D4">json</span></span>
<span class="line"><span style="color: #D4D4D4">├─ composer</span><span style="color: #D4D4D4">.</span><span style="color: #D4D4D4">lock</span></span>
<span class="line"><span style="color: #D4D4D4">├─ phpunit</span><span style="color: #D4D4D4">.</span><span style="color: #D4D4D4">xml</span></span>
<span class="line"><span style="color: #D4D4D4">├─ examples/</span></span>
<span class="line"><span style="color: #D4D4D4">│  └─ geometric_mean_demo</span><span style="color: #D4D4D4">.</span><span style="color: #D4D4D4">php</span></span>
<span class="line"><span style="color: #D4D4D4">│  └─ harmonic_mean_demo</span><span style="color: #D4D4D4">.</span><span style="color: #D4D4D4">php</span></span>
<span class="line"><span style="color: #D4D4D4">│  └─ iqr_demo</span><span style="color: #D4D4D4">.</span><span style="color: #D4D4D4">php</span></span>
<span class="line"><span style="color: #D4D4D4">│  └─ mad_demo</span><span style="color: #D4D4D4">.</span><span style="color: #D4D4D4">php</span></span>
<span class="line"><span style="color: #D4D4D4">│  └─ mean_demo</span><span style="color: #D4D4D4">.</span><span style="color: #D4D4D4">php</span></span>
<span class="line"><span style="color: #D4D4D4">│  └─ median_demo</span><span style="color: #D4D4D4">.</span><span style="color: #D4D4D4">php</span></span>
<span class="line"><span style="color: #D4D4D4">│  └─ min_max_demo</span><span style="color: #D4D4D4">.</span><span style="color: #D4D4D4">php</span></span>
<span class="line"><span style="color: #D4D4D4">│  └─ mode_demo</span><span style="color: #D4D4D4">.</span><span style="color: #D4D4D4">php</span></span>
<span class="line"><span style="color: #D4D4D4">│  └─ percentile_demo</span><span style="color: #D4D4D4">.</span><span style="color: #D4D4D4">php</span></span>
<span class="line"><span style="color: #D4D4D4">│  └─ range_demo</span><span style="color: #D4D4D4">.</span><span style="color: #D4D4D4">php</span></span>
<span class="line"><span style="color: #D4D4D4">│  └─ standard_deviation_demo</span><span style="color: #D4D4D4">.</span><span style="color: #D4D4D4">php</span></span>
<span class="line"><span style="color: #D4D4D4">│  └─ trimmed_mean_demo</span><span style="color: #D4D4D4">.</span><span style="color: #D4D4D4">php</span></span>
<span class="line"><span style="color: #D4D4D4">│  └─ variance_demo</span><span style="color: #D4D4D4">.</span><span style="color: #D4D4D4">php</span></span>
<span class="line"><span style="color: #D4D4D4">├─ src/</span></span>
<span class="line"><span style="color: #D4D4D4">│  └─ DescriptiveStats</span><span style="color: #D4D4D4">.</span><span style="color: #D4D4D4">php</span></span>
<span class="line"><span style="color: #D4D4D4">├─ tests/</span></span>
<span class="line"><span style="color: #D4D4D4">│  └─ DescriptiveStatsTest</span><span style="color: #D4D4D4">.</span><span style="color: #D4D4D4">php</span></span>
<span class="line"><span style="color: #D4D4D4">└─ vendor/</span></span>
<span class="line"><span style="color: #D4D4D4">    └─ autoload</span><span style="color: #D4D4D4">.</span><span style="color: #D4D4D4">php</span></span></code></pre></div>



<p class="wp-block-paragraph">Nel terminale, all&#8217;interno della cartella del progetto digitiamo il comando: </p>



<p class="wp-block-paragraph"><code>composer init</code></p>



<p class="wp-block-paragraph">Composer ci chiederà alcune informazioni partendo dal Package name che viene espresso come vendor/package-name. Nel mio caso essendo il mio account denominato &#8220;thesimon82&#8221; il nome del pacchetto sarà <code>thesimon82/descriptive-statistics</code>. Confermiamo con invio.</p>



<p class="wp-block-paragraph">Ora ci viene chiesta la descrizione, per questo progetto inseriamo: <code>Lightweight PHP class for descriptive statistics</code>.</p>



<p class="wp-block-paragraph">L&#8217;autore e ci viene restituito l&#8217;autore di default se l&#8217;avevamo già impostato, altrimenti inseriamo il nostro nome e cognome. </p>



<p class="wp-block-paragraph">Minimum stability, se è una versione stabile inseriamo &#8220;stable&#8221;.</p>



<p class="wp-block-paragraph">Per Package Type inseriamo: &#8220;library&#8221;</p>



<p class="wp-block-paragraph">In license: MIT</p>



<p class="wp-block-paragraph">Ci viene chiesto se vogliamo inserire, uno per uno, i pacchetti di produzione (require) che la libreria necessita per funzionare. In questo caso la classe è stand-alone (usa solo funzioni native di PHP), quindi non abbiamo altre dipendenze oltre alle versione minima di PHP pertanto possiamo anche dichiarare &#8220;no&#8221;. Se stai pensando a PHPUnit per i test sui metodi della classe, ti ricordo che PHPUnit è stato settato solo per la fase di sviluppo e test pertanto va inserito in require-dev e non in require. In questo modo chi installerà il pacchetto in produzione non si troverà PHPUnit tra le dipendenze di runtime. </p>



<p class="wp-block-paragraph">La domanda successiva infatti richiede proprio se ho intenzione di definire le mie dipendenze dev in modo interattivo (require-dev), qui digitiamo &#8220;yes&#8221; e ci chiederà di inserire il nome del pacchetto. Digitiamo ora <code>phpunit/phpunit</code>. Ci darà una lista di pacchetti trovati e selezioniamo phpunit/phpunit con il numero corrispondente. Confermiamo con invio e ci viene chiesto quale versione intendiamo includere. Confermiamo semplicemente con invio per installare l&#8217;ultima versione.</p>



<p class="wp-block-paragraph">Ci chiederà ora se vogliamo installare altri pacchetti di dipendenze, ma non ne abbiamo altri quindi premiamo semplicemente invio. <br>Ora ci chiederà se intendiamo aggiungere un mapping PSR-4 per l&#8217;autoload delle classi chiedendoci di mappare il namespace Thesimon82DescriptiveStatistics ma nel progetto avevamo utilizzato Renor\Statistics quindi digitiamo n per skippare la proposta.</p>



<p class="wp-block-paragraph">Finalmente otteniamo un resoconto dei dati inseriti:</p>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#1E1E1E"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" data-code="{
    &quot;name&quot;: &quot;thesimon82/descriptive-statistics&quot;,
    &quot;description&quot;: &quot;Lightweight PHP class for descriptive statistics&quot;,
    &quot;type&quot;: &quot;library&quot;,
    &quot;require-dev&quot;: {
        &quot;phpunit/phpunit&quot;: &quot;^12.1&quot;
    },
    &quot;license&quot;: &quot;MIT&quot;,
    &quot;authors&quot;: [
        {
            &quot;name&quot;: &quot;Simone Renzi&quot;,
            &quot;email&quot;: &quot;info@simonerenzi.com&quot;
        }
    ],
    &quot;minimum-stability&quot;: &quot;stable&quot;,
    &quot;require&quot;: {},
    &quot;autoload&quot;: {
        &quot;psr-4&quot;: {
            &quot;Renor\Statistics\&quot;: &quot;src/&quot;
        }
    }
}

Do you confirm generation [yes]? " style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"><span style="color: #D4D4D4">{</span></span>
<span class="line"><span style="color: #D4D4D4">    &quot;name&quot;: &quot;thesimon82/descriptive-statistics&quot;,</span></span>
<span class="line"><span style="color: #D4D4D4">    &quot;description&quot;: &quot;Lightweight PHP class for descriptive statistics&quot;,</span></span>
<span class="line"><span style="color: #D4D4D4">    &quot;type&quot;: &quot;library&quot;,</span></span>
<span class="line"><span style="color: #D4D4D4">    &quot;require-dev&quot;: {</span></span>
<span class="line"><span style="color: #D4D4D4">        &quot;phpunit/phpunit&quot;: &quot;^12.1&quot;</span></span>
<span class="line"><span style="color: #D4D4D4">    },</span></span>
<span class="line"><span style="color: #D4D4D4">    &quot;license&quot;: &quot;MIT&quot;,</span></span>
<span class="line"><span style="color: #D4D4D4">    &quot;authors&quot;: [</span></span>
<span class="line"><span style="color: #D4D4D4">        {</span></span>
<span class="line"><span style="color: #D4D4D4">            &quot;name&quot;: &quot;Simone Renzi&quot;,</span></span>
<span class="line"><span style="color: #D4D4D4">            &quot;email&quot;: &quot;info@simonerenzi.com&quot;</span></span>
<span class="line"><span style="color: #D4D4D4">        }</span></span>
<span class="line"><span style="color: #D4D4D4">    ],</span></span>
<span class="line"><span style="color: #D4D4D4">    &quot;minimum-stability&quot;: &quot;stable&quot;,</span></span>
<span class="line"><span style="color: #D4D4D4">    &quot;require&quot;: {},</span></span>
<span class="line"><span style="color: #D4D4D4">    &quot;autoload&quot;: {</span></span>
<span class="line"><span style="color: #D4D4D4">        &quot;psr-4&quot;: {</span></span>
<span class="line"><span style="color: #D4D4D4">            &quot;Renor\Statistics\&quot;: &quot;src/&quot;</span></span>
<span class="line"><span style="color: #D4D4D4">        }</span></span>
<span class="line"><span style="color: #D4D4D4">    }</span></span>
<span class="line"><span style="color: #D4D4D4">}</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4">Do you confirm generation [yes]? </span></span></code></pre></div>



<p class="wp-block-paragraph">Qui controlliamo i dati e se tutto è giusto confermiamo con &#8220;yes&#8221; e installiamo le dipendenze.</p>



<p class="wp-block-paragraph">Al termine digitiamo il comando:</p>



<p class="wp-block-paragraph"><code>composer dump-autoload</code> per rigenerare l&#8217;autoloader delle classi.</p>



<p class="wp-block-paragraph">È arrivato il momento di fare il commit con questa serie di comandi: </p>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#1E1E1E"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" data-code="git add .
git commit -m &quot;feat: first stable release&quot;
git tag v1.0.0
git push origin main v1.0.0" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"><span style="color: #D4D4D4">git add .</span></span>
<span class="line"><span style="color: #D4D4D4">git commit -m &quot;feat: first stable release&quot;</span></span>
<span class="line"><span style="color: #D4D4D4">git tag v1.0.0</span></span>
<span class="line"><span style="color: #D4D4D4">git push origin main v1.0.0</span></span></code></pre></div>



<p class="wp-block-paragraph">Ora ci muoviamo su GitHub e dovremmo vedere la nostra repo con l&#8217;ultimo commit, nel mio caso thesimon82 feat: first stable release.</p>



<p class="wp-block-paragraph">Copiamo l&#8217;URL in alto sulla barra degli indirizzi e ci spostiamo su packagist.</p>



<p class="wp-block-paragraph">Clicchiamo in alto su &#8220;Submit&#8221; e incolliamo nel campo di testo il link di GitHub che abbiamo copiato. Poi premiamo il pulsante Check. A questo punto Packagist analizzerà il composer.json e mostrerà subito la scheda del pacchetto. Cliccando sul pulsante in basso &#8220;Submit&#8221; viene creato il Package. </p>



<p class="wp-block-paragraph">Abbiamo terminato, ora è il momento di testare il funzionamento.</p>



<p class="wp-block-paragraph">Creiamo una nuova cartella &#8220;Stats Test&#8221; poi andiamo su terminale ed entriamo all&#8217;interno della cartella. <br>Qui digitiamo:</p>



<p class="wp-block-paragraph"><code>composer require thesimon82/descriptive-statistics</code></p>



<p class="wp-block-paragraph">Ora importiamo questa cartella all&#8217;interno del nostro ambiente di sviluppo e creiamo un nuovo file nella root: test.php</p>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#1E1E1E"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" data-code="&lt;?php
require_once 'vendor/autoload.php';
use RenorStatisticsDescriptiveStats;

$stats = new DescriptiveStats([1, 2, 3, 4, 5,6.22]);
echo $stats-&gt;mean();" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"><span style="color: #D4D4D4">&lt;?php</span></span>
<span class="line"><span style="color: #C586C0">require_once</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">&#39;vendor/autoload.php&#39;</span><span style="color: #D4D4D4">;</span></span>
<span class="line"><span style="color: #569CD6">use</span><span style="color: #D4D4D4"> RenorStatistics</span><span style="color: #4EC9B0">DescriptiveStats</span><span style="color: #D4D4D4">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #9CDCFE">$stats</span><span style="color: #D4D4D4"> = </span><span style="color: #569CD6">new</span><span style="color: #D4D4D4"> </span><span style="color: #4EC9B0">DescriptiveStats</span><span style="color: #D4D4D4">([</span><span style="color: #B5CEA8">1</span><span style="color: #D4D4D4">, </span><span style="color: #B5CEA8">2</span><span style="color: #D4D4D4">, </span><span style="color: #B5CEA8">3</span><span style="color: #D4D4D4">, </span><span style="color: #B5CEA8">4</span><span style="color: #D4D4D4">, </span><span style="color: #B5CEA8">5</span><span style="color: #D4D4D4">,</span><span style="color: #B5CEA8">6.22</span><span style="color: #D4D4D4">]);</span></span>
<span class="line"><span style="color: #DCDCAA">echo</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">$stats</span><span style="color: #D4D4D4">-&gt;</span><span style="color: #DCDCAA">mean</span><span style="color: #D4D4D4">();</span></span></code></pre></div>



<p class="wp-block-paragraph">Come possiamo vedere, stiamo includendo l&#8217;autoloader generato da Composer in cui tutti le classi mappate con PSR-4 diventano disponibili senza ulteriori require. </p>



<p class="wp-block-paragraph">Definiamo il namespace utilizzato nella classe DescriptiveStats e istanziamo un nuovo oggetto con un dataset numerico. Ti ricorderai che il costruttore della classe filtrava automaticamente eventuali valori non numerici, riallineava le chiavi dell&#8217;array e lanciava un&#8217;eccezione se l&#8217;insieme fosse risultato vuoto. Viene quindi richiamato il metodo <code>mean()</code> che esegue la media e lo visualizza a schermo. </p>



<p class="wp-block-paragraph">Se adesso dal terminale lanci il comando <code>php test.php</code> se hai fatto tutto correttamente dovresti avere come risultato 3.5366666666667 che è proprio la media approssimata dei valori che abbiamo passato al costruttore della classe. </p>



<h2 class="wp-block-heading">Conclusioni</h2>



<p class="wp-block-paragraph">Abbiamo visto come trasformare una semplice classe PHP in un pacchetto Composer distribuito su Packagist. Ora la libreria può essere installata con un unico comando, beneficia di versionamento semantico, integrazione continua e di un&#8217;automazione che aggiorna automaticamente la scheda su Packagist a ogni nuovo tag. </p>



<p class="wp-block-paragraph">Da questo momento il ciclo di vita è lineare: implementi una funazionalità, esegui i test, incrementi la versione, crei il tag e fa il push su GitHub. Packagist e Composer faranno il resto!</p>



<p class="wp-block-paragraph">[starbox]</p>
<p>L'articolo <a href="https://renor.it/blog/sviluppo-software-programmazione/da-zero-a-packagist-pubblicare-una-libreria-php-su-composer/">Da Zero a Packagist: pubblicare una libreria PHP su Composer</a> proviene da <a href="https://renor.it">RENOR &amp; Partners S.r.l.</a>.</p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Una Classe di Statistica descrittiva in PHP</title>
		<link>https://renor.it/blog/sviluppo-software-programmazione/una-classe-di-statistica-descrittiva-in-php/</link>
		
		<dc:creator><![CDATA[Simone Renzi]]></dc:creator>
		<pubDate>Mon, 12 May 2025 21:06:41 +0000</pubDate>
				<category><![CDATA[Sviluppo Software & Programmazione]]></category>
		<category><![CDATA[analisi dati]]></category>
		<category><![CDATA[Composer]]></category>
		<category><![CDATA[deviazione standard]]></category>
		<category><![CDATA[errore standard]]></category>
		<category><![CDATA[IQR]]></category>
		<category><![CDATA[libreria PHP]]></category>
		<category><![CDATA[matematica applicata]]></category>
		<category><![CDATA[media aritmetica]]></category>
		<category><![CDATA[mediana]]></category>
		<category><![CDATA[moda]]></category>
		<category><![CDATA[Packagist]]></category>
		<category><![CDATA[percentili]]></category>
		<category><![CDATA[php]]></category>
		<category><![CDATA[programmazione]]></category>
		<category><![CDATA[scarto assoluto medio]]></category>
		<category><![CDATA[statistica descrittiva]]></category>
		<category><![CDATA[tutorial PHP]]></category>
		<category><![CDATA[varianza]]></category>
		<guid isPermaLink="false">https://renor.it/?p=444</guid>

					<description><![CDATA[<p>Nel mondo dello sviluppo software l&#8217;analisi dei dati è sempre più centrale. Con l&#8217;avvento dell&#8217;intelligenza artificiale nel mercato consumer molti la utilizzano anche per analizzare dati statistici. In molti casi però l&#8217;uso di questa tecnologia non è richiesta ed è anzi meno efficiente di un solido algoritmo che si occupi di prendere dati in ingresso [&#8230;]</p>
<p>L'articolo <a href="https://renor.it/blog/sviluppo-software-programmazione/una-classe-di-statistica-descrittiva-in-php/">Una Classe di Statistica descrittiva in PHP</a> proviene da <a href="https://renor.it">RENOR &amp; Partners S.r.l.</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p class="wp-block-paragraph">Nel mondo dello sviluppo software l&#8217;analisi dei dati è sempre più centrale. Con l&#8217;avvento dell&#8217;intelligenza artificiale nel mercato consumer molti la utilizzano anche per analizzare dati statistici. In molti casi però l&#8217;uso di questa tecnologia non è richiesta ed è anzi meno efficiente di un solido algoritmo che si occupi di prendere dati in ingresso e restituire &#8220;black-box&#8221; dati in uscita.</p>



<p class="wp-block-paragraph">L&#8217;intelligenza artificiale è ormai interpretata da molti imprenditori come una moda ma andrebbe utilizzata solo laddove è veramente un valore aggiunto. Parlando di efficienza, utilizzare l&#8217;intelligenza artificiale per calcolare una media, una mediana, una moda non è solamente come sparare con un bazooka per uccidere un paio di mosche ma può rivelarsi anche più lenta, dal momento che bisogna calcolare i tempi di inferenza, rispetto ad un algoritmo a stati finiti. </p>



<p class="wp-block-paragraph">Anche in contesti non strettamente scientifici o accademici, conoscere i fondamenti della statistica descrittiva, può rivelarsi estremamente utile: dalla generazione di report automatizzati, al monitoraggio delle performance di un&#8217;applicazione, fino alla costruzione di dashboard o strumenti analitici. </p>



<p class="wp-block-paragraph">In questo articolo realizzeremo una classe PHP che calcola i principali indicatori statistici descrittivi, come media, mediana, moda, varianza, deviazione standard, quartili, ecc., partendo da zero, senza librerie esterne. Il codice sarà pulito, riutilizzabile e pronto per essere trasfromato in un pacchetto Composer su cui verrà realizzato un altro articolo. </p>



<h2 class="wp-block-heading">Progettare una classe semplice ma estensibile</h2>



<p class="wp-block-paragraph">Per costruire una classe di statistica descrittiva utile e facilmente integrabile in altri progetti, adotteremo una struttura ad oggetti aderente ai principi SOLID, evitando dipendenze esterne e garantendo la possibilità di estensoine futura (es. supporto a dataset associativi o lettura da file CSV). </p>



<p class="wp-block-paragraph">La classe sarà progettata per lavorare su array di valori numerici, e calcolare in modo efficiente i principali indici statistici. L&#8217;obiettivo è offrire un&#8217;interfaccia semplice. </p>



<p class="wp-block-paragraph">Per prima cosa andiamo a creare una nuova repo su GitHub, la trovate al link:<br><a href="https://github.com/thesimon82/descriptive-statistics-php">https://github.com/thesimon82/descriptive-statistics-php</a></p>



<p class="wp-block-paragraph">Iniziamo ad implementare i metodi.</p>



<p class="wp-block-paragraph">La struttura del progetto dovrà avere questa forma: </p>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#1E1E1E"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" data-code="descriptive-statistics-php/
├─ composer.json
├─ composer.lock
├─ phpunit.xml
├─ examples/
│  └─ geometric_mean_demo.php
│  └─ harmonic_mean_demo.php
│  └─ iqr_demo.php
│  └─ mad_demo.php
│  └─ mean_demo.php
│  └─ median_demo.php
│  └─ min_max_demo.php
│  └─ mode_demo.php
│  └─ percentile_demo.php
│  └─ range_demo.php
│  └─ standard_deviation_demo.php
│  └─ trimmed_mean_demo.php
│  └─ variance_demo.php
├─ src/
│  └─ DescriptiveStats.php
├─ tests/
│  └─ DescriptiveStatsTest.php
└─ vendor/
    └─ autoload.php" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"><span style="color: #D4D4D4">descriptive-statistics-php/</span></span>
<span class="line"><span style="color: #D4D4D4">├─ composer</span><span style="color: #D4D4D4">.</span><span style="color: #D4D4D4">json</span></span>
<span class="line"><span style="color: #D4D4D4">├─ composer</span><span style="color: #D4D4D4">.</span><span style="color: #D4D4D4">lock</span></span>
<span class="line"><span style="color: #D4D4D4">├─ phpunit</span><span style="color: #D4D4D4">.</span><span style="color: #D4D4D4">xml</span></span>
<span class="line"><span style="color: #D4D4D4">├─ examples/</span></span>
<span class="line"><span style="color: #D4D4D4">│  └─ geometric_mean_demo</span><span style="color: #D4D4D4">.</span><span style="color: #D4D4D4">php</span></span>
<span class="line"><span style="color: #D4D4D4">│  └─ harmonic_mean_demo</span><span style="color: #D4D4D4">.</span><span style="color: #D4D4D4">php</span></span>
<span class="line"><span style="color: #D4D4D4">│  └─ iqr_demo</span><span style="color: #D4D4D4">.</span><span style="color: #D4D4D4">php</span></span>
<span class="line"><span style="color: #D4D4D4">│  └─ mad_demo</span><span style="color: #D4D4D4">.</span><span style="color: #D4D4D4">php</span></span>
<span class="line"><span style="color: #D4D4D4">│  └─ mean_demo</span><span style="color: #D4D4D4">.</span><span style="color: #D4D4D4">php</span></span>
<span class="line"><span style="color: #D4D4D4">│  └─ median_demo</span><span style="color: #D4D4D4">.</span><span style="color: #D4D4D4">php</span></span>
<span class="line"><span style="color: #D4D4D4">│  └─ min_max_demo</span><span style="color: #D4D4D4">.</span><span style="color: #D4D4D4">php</span></span>
<span class="line"><span style="color: #D4D4D4">│  └─ mode_demo</span><span style="color: #D4D4D4">.</span><span style="color: #D4D4D4">php</span></span>
<span class="line"><span style="color: #D4D4D4">│  └─ percentile_demo</span><span style="color: #D4D4D4">.</span><span style="color: #D4D4D4">php</span></span>
<span class="line"><span style="color: #D4D4D4">│  └─ range_demo</span><span style="color: #D4D4D4">.</span><span style="color: #D4D4D4">php</span></span>
<span class="line"><span style="color: #D4D4D4">│  └─ standard_deviation_demo</span><span style="color: #D4D4D4">.</span><span style="color: #D4D4D4">php</span></span>
<span class="line"><span style="color: #D4D4D4">│  └─ trimmed_mean_demo</span><span style="color: #D4D4D4">.</span><span style="color: #D4D4D4">php</span></span>
<span class="line"><span style="color: #D4D4D4">│  └─ variance_demo</span><span style="color: #D4D4D4">.</span><span style="color: #D4D4D4">php</span></span>
<span class="line"><span style="color: #D4D4D4">├─ src/</span></span>
<span class="line"><span style="color: #D4D4D4">│  └─ DescriptiveStats</span><span style="color: #D4D4D4">.</span><span style="color: #D4D4D4">php</span></span>
<span class="line"><span style="color: #D4D4D4">├─ tests/</span></span>
<span class="line"><span style="color: #D4D4D4">│  └─ DescriptiveStatsTest</span><span style="color: #D4D4D4">.</span><span style="color: #D4D4D4">php</span></span>
<span class="line"><span style="color: #D4D4D4">└─ vendor/</span></span>
<span class="line"><span style="color: #D4D4D4">    └─ autoload</span><span style="color: #D4D4D4">.</span><span style="color: #D4D4D4">php</span></span></code></pre></div>



<p class="wp-block-paragraph">Come puoi notare ho previsto anche una cartella per l&#8217;inserimento dei test sui metodi della classe (opzionale) con phpunit. Il file phpunit.xml definisce la cartella dei test ed i sorgenti di phpunit che deve essere installato tramite composer alla repo packagist <code>phpunit/phpunit</code> inserendolo come dipendenza di sviluppo tramite il comando <code>composer require --dev phpunit/phpunit ^10</code>.</p>



<h2 class="wp-block-heading">Media</h2>



<p class="wp-block-paragraph">La <strong>media aritmetica</strong> (o valore medio) di un insieme di <img loading="lazy" decoding="async" src="https://renor.it/wp-content/ql-cache/quicklatex.com-b170995d512c659d8668b4e42e1fef6b_l3.png" class="ql-img-inline-formula quicklatex-auto-format" alt="&#110;" title="Rendered by QuickLaTeX.com" height="8" width="11" style="vertical-align: 0px;"/> osservazioni numeriche <img loading="lazy" decoding="async" src="https://renor.it/wp-content/ql-cache/quicklatex.com-5e8319f54f72e7dac2238515c1499b27_l3.png" class="ql-img-inline-formula quicklatex-auto-format" alt="&#120;&#95;&#49;&#44;&#32;&#120;&#95;&#50;&#44;&#32;&#92;&#100;&#111;&#116;&#115;&#44;&#32;&#120;&#95;&#110;" title="Rendered by QuickLaTeX.com" height="12" width="101" style="vertical-align: -4px;"/> si ottiene sommando tutti i valori e dividendo il risultato per il numero totale di osservazioni. Formalmente si scrive:</p>



<p class="wp-block-paragraph"><br><img loading="lazy" decoding="async" src="https://renor.it/wp-content/ql-cache/quicklatex.com-6e56531130e72a8ea51283096d7d0308_l3.png" class="ql-img-inline-formula quicklatex-auto-format" alt="&#92;&#98;&#97;&#114;&#123;&#120;&#125;&#32;&#92;&#59;&#61;&#92;&#59;&#32;&#92;&#102;&#114;&#97;&#99;&#123;&#49;&#125;&#123;&#110;&#125;&#32;&#92;&#115;&#117;&#109;&#95;&#123;&#105;&#61;&#49;&#125;&#94;&#123;&#110;&#125;&#32;&#120;&#95;&#105;" title="Rendered by QuickLaTeX.com" height="22" width="119" style="vertical-align: -6px;"/></p>



<p class="wp-block-paragraph"><br>dove <img loading="lazy" decoding="async" src="https://renor.it/wp-content/ql-cache/quicklatex.com-20ebc7ea21d727ebe3840c06a433ab09_l3.png" class="ql-img-inline-formula quicklatex-auto-format" alt="&#92;&#98;&#97;&#114;&#123;&#120;&#125;" title="Rendered by QuickLaTeX.com" height="11" width="10" style="vertical-align: 0px;"/> rappresenta la media aritmetica, <img loading="lazy" decoding="async" src="https://renor.it/wp-content/ql-cache/quicklatex.com-b170995d512c659d8668b4e42e1fef6b_l3.png" class="ql-img-inline-formula quicklatex-auto-format" alt="&#110;" title="Rendered by QuickLaTeX.com" height="8" width="11" style="vertical-align: 0px;"/> è la cardinalità del campione e <img loading="lazy" decoding="async" src="https://renor.it/wp-content/ql-cache/quicklatex.com-3753926091c62342a46ec13bbebace46_l3.png" class="ql-img-inline-formula quicklatex-auto-format" alt="&#92;&#115;&#117;&#109;&#95;&#123;&#105;&#61;&#49;&#125;&#94;&#123;&#110;&#125;&#32;&#120;&#95;&#105;" title="Rendered by QuickLaTeX.com" height="19" width="60" style="vertical-align: -5px;"/> indica la somma di tutte le osservazioni. Questa misura fornisce un’indicazione sintetica della tendenza centrale dei dati, pur essendo sensibile alla presenza di valori anomali (outlier) che possono farla divergere significativamente dal “centro” reale della distribuzione.</p>



<p class="wp-block-paragraph">Implementiamo questo metodo nella nostra classe <code>DescriptiveStats.php</code></p>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#1E1E1E"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" data-code="&lt;?php

declare(strict_types=1);

namespace RenorStatistics;

/**
 * Class DescriptiveStats
 *
 * A lightweight class to perform basic descriptive statistics on numeric datasets.
 */
class DescriptiveStats
{
    /**
     * @var float[] Filtered and normalized numeric dataset.
     */
    private array $data;

    /**
     * Main constructor.
     *
     * @param array $data An array containing the numeric values to be analyzed.
     * @throws InvalidArgumentException If the array is empty or contains no numeric values.
     */
    public function __construct(array $data)
    {
        // Filter only numeric values (int or float) and reset array keys
        $filtered = array_filter($data, 'is_numeric');
        $this-&gt;data = array_values($filtered);

        if (count($this-&gt;data) === 0) {
            throw new InvalidArgumentException('The dataset must contain at least one numeric value.');
        }
    }

    /**
     * Calculates the arithmetic mean of the dataset.
     *
     * @return float The arithmetic mean.
     */
    public function mean(): float
    {
        return array_sum($this-&gt;data) / count($this-&gt;data);
    }
}" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"><span style="color: #D4D4D4">&lt;?php</span></span>
<span class="line"></span>
<span class="line"><span style="color: #C586C0">declare</span><span style="color: #D4D4D4">(strict_types=</span><span style="color: #B5CEA8">1</span><span style="color: #D4D4D4">);</span></span>
<span class="line"></span>
<span class="line"><span style="color: #569CD6">namespace</span><span style="color: #D4D4D4"> </span><span style="color: #4EC9B0">RenorStatistics</span><span style="color: #D4D4D4">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #6A9955">/**</span></span>
<span class="line"><span style="color: #6A9955"> * Class DescriptiveStats</span></span>
<span class="line"><span style="color: #6A9955"> *</span></span>
<span class="line"><span style="color: #6A9955"> * A lightweight class to perform basic descriptive statistics on numeric datasets.</span></span>
<span class="line"><span style="color: #6A9955"> */</span></span>
<span class="line"><span style="color: #569CD6">class</span><span style="color: #D4D4D4"> </span><span style="color: #4EC9B0">DescriptiveStats</span></span>
<span class="line"><span style="color: #D4D4D4">{</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #6A9955">/**</span></span>
<span class="line"><span style="color: #6A9955">     * </span><span style="color: #569CD6">@var</span><span style="color: #6A9955"> </span><span style="color: #569CD6">float[]</span><span style="color: #6A9955"> Filtered and normalized numeric dataset.</span></span>
<span class="line"><span style="color: #6A9955">     */</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #569CD6">private</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">array</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">$data</span><span style="color: #D4D4D4">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #6A9955">/**</span></span>
<span class="line"><span style="color: #6A9955">     * Main constructor.</span></span>
<span class="line"><span style="color: #6A9955">     *</span></span>
<span class="line"><span style="color: #6A9955">     * </span><span style="color: #569CD6">@param</span><span style="color: #6A9955"> </span><span style="color: #569CD6">array</span><span style="color: #6A9955"> $data An array containing the numeric values to be analyzed.</span></span>
<span class="line"><span style="color: #6A9955">     * </span><span style="color: #569CD6">@throws</span><span style="color: #6A9955"> </span><span style="color: #4EC9B0">InvalidArgumentException</span><span style="color: #6A9955"> If the array is empty or contains no numeric values.</span></span>
<span class="line"><span style="color: #6A9955">     */</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #569CD6">public</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">function</span><span style="color: #D4D4D4"> </span><span style="color: #DCDCAA">__construct</span><span style="color: #D4D4D4">(</span><span style="color: #569CD6">array</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">$data</span><span style="color: #D4D4D4">)</span></span>
<span class="line"><span style="color: #D4D4D4">    {</span></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #6A9955">// Filter only numeric values (int or float) and reset array keys</span></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #9CDCFE">$filtered</span><span style="color: #D4D4D4"> = </span><span style="color: #DCDCAA">array_filter</span><span style="color: #D4D4D4">(</span><span style="color: #9CDCFE">$data</span><span style="color: #D4D4D4">, </span><span style="color: #CE9178">&#39;is_numeric&#39;</span><span style="color: #D4D4D4">);</span></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #569CD6">$this</span><span style="color: #D4D4D4">-&gt;</span><span style="color: #9CDCFE">data</span><span style="color: #D4D4D4"> = </span><span style="color: #DCDCAA">array_values</span><span style="color: #D4D4D4">(</span><span style="color: #9CDCFE">$filtered</span><span style="color: #D4D4D4">);</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #C586C0">if</span><span style="color: #D4D4D4"> (</span><span style="color: #DCDCAA">count</span><span style="color: #D4D4D4">(</span><span style="color: #569CD6">$this</span><span style="color: #D4D4D4">-&gt;</span><span style="color: #9CDCFE">data</span><span style="color: #D4D4D4">) === </span><span style="color: #B5CEA8">0</span><span style="color: #D4D4D4">) {</span></span>
<span class="line"><span style="color: #D4D4D4">            </span><span style="color: #C586C0">throw</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">new</span><span style="color: #D4D4D4"> </span><span style="color: #4EC9B0">InvalidArgumentException</span><span style="color: #D4D4D4">(</span><span style="color: #CE9178">&#39;The dataset must contain at least one numeric value.&#39;</span><span style="color: #D4D4D4">);</span></span>
<span class="line"><span style="color: #D4D4D4">        }</span></span>
<span class="line"><span style="color: #D4D4D4">    }</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #6A9955">/**</span></span>
<span class="line"><span style="color: #6A9955">     * Calculates the arithmetic mean of the dataset.</span></span>
<span class="line"><span style="color: #6A9955">     *</span></span>
<span class="line"><span style="color: #6A9955">     * </span><span style="color: #569CD6">@return</span><span style="color: #6A9955"> </span><span style="color: #569CD6">float</span><span style="color: #6A9955"> The arithmetic mean.</span></span>
<span class="line"><span style="color: #6A9955">     */</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #569CD6">public</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">function</span><span style="color: #D4D4D4"> </span><span style="color: #DCDCAA">mean</span><span style="color: #D4D4D4">(): </span><span style="color: #569CD6">float</span></span>
<span class="line"><span style="color: #D4D4D4">    {</span></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #C586C0">return</span><span style="color: #D4D4D4"> </span><span style="color: #DCDCAA">array_sum</span><span style="color: #D4D4D4">(</span><span style="color: #569CD6">$this</span><span style="color: #D4D4D4">-&gt;</span><span style="color: #9CDCFE">data</span><span style="color: #D4D4D4">) / </span><span style="color: #DCDCAA">count</span><span style="color: #D4D4D4">(</span><span style="color: #569CD6">$this</span><span style="color: #D4D4D4">-&gt;</span><span style="color: #9CDCFE">data</span><span style="color: #D4D4D4">);</span></span>
<span class="line"><span style="color: #D4D4D4">    }</span></span>
<span class="line"><span style="color: #D4D4D4">}</span></span></code></pre></div>



<p class="wp-block-paragraph">Come puoi notare abbiamo dichiarato lo strict_types. Questa opzione impone a PHP di non effettuare il cast automatico del valori. Questo è necessario per avere il pieno controllo del tipo di dato. </p>



<p class="wp-block-paragraph">Dal momento che accetteremo i dati come un array di valori dichiariamo una proprietà privata della classe <code>private array $data</code>.</p>



<p class="wp-block-paragraph">Nel costruttore della classe ci occupiamo di recuperare i dati che vengono passati quando andremo ad istanziare la classe per creare un nuovo oggetto, verificando che il contenuto dell&#8217;array <code>$data</code> sia di tipo numerico, ed andiamo a posizionare i valori all&#8217;interno della proprietà <code>$this-&gt;data</code>.</p>



<p class="wp-block-paragraph">Nel metodo <code>mean()</code> andiamo a implementare la formula matematica della media: sommiamo tutti gli elementi dell&#8217;array passato e dividiamo per il numero di elementi ritornando il risultato. </p>



<h2 class="wp-block-heading">Mediana</h2>



<p class="wp-block-paragraph">La mediana rappresenta il valore centrale di un insieme ordinato di osservazioni e suddivide il campione in due metà di egual numerosità. Data una serie di <img loading="lazy" decoding="async" src="https://renor.it/wp-content/ql-cache/quicklatex.com-b170995d512c659d8668b4e42e1fef6b_l3.png" class="ql-img-inline-formula quicklatex-auto-format" alt="&#110;" title="Rendered by QuickLaTeX.com" height="8" width="11" style="vertical-align: 0px;"/> valori <img loading="lazy" decoding="async" src="https://renor.it/wp-content/ql-cache/quicklatex.com-5e8319f54f72e7dac2238515c1499b27_l3.png" class="ql-img-inline-formula quicklatex-auto-format" alt="&#120;&#95;&#49;&#44;&#32;&#120;&#95;&#50;&#44;&#32;&#92;&#100;&#111;&#116;&#115;&#44;&#32;&#120;&#95;&#110;" title="Rendered by QuickLaTeX.com" height="12" width="101" style="vertical-align: -4px;"/> tali che <img loading="lazy" decoding="async" src="https://renor.it/wp-content/ql-cache/quicklatex.com-a8df85ae09e9285340b9227eddc7d1ab_l3.png" class="ql-img-inline-formula quicklatex-auto-format" alt="&#120;&#95;&#49;&#32;&#92;&#108;&#101;&#32;&#120;&#95;&#50;&#32;&#92;&#108;&#101;&#32;&#92;&#100;&#111;&#116;&#115;&#32;&#92;&#108;&#101;&#32;&#120;&#95;&#110;" title="Rendered by QuickLaTeX.com" height="15" width="145" style="vertical-align: -3px;"/>:</p>



<ul class="wp-block-list">
<li>Se <img loading="lazy" decoding="async" src="https://renor.it/wp-content/ql-cache/quicklatex.com-b170995d512c659d8668b4e42e1fef6b_l3.png" class="ql-img-inline-formula quicklatex-auto-format" alt="&#110;" title="Rendered by QuickLaTeX.com" height="8" width="11" style="vertical-align: 0px;"/> è dispari, la mediana è semplicemente l’elemento in posizione <img loading="lazy" decoding="async" src="https://renor.it/wp-content/ql-cache/quicklatex.com-1450a1ab44bcfe30d8b103b06e9cd5bd_l3.png" class="ql-img-inline-formula quicklatex-auto-format" alt="&#92;&#102;&#114;&#97;&#99;&#123;&#110;&#43;&#49;&#125;&#123;&#50;&#125;" title="Rendered by QuickLaTeX.com" height="22" width="26" style="vertical-align: -6px;"/>: <br><img loading="lazy" decoding="async" src="https://renor.it/wp-content/ql-cache/quicklatex.com-74af485cea698cf57cdd7075ad9caf15_l3.png" class="ql-img-inline-formula quicklatex-auto-format" alt="&#92;&#116;&#101;&#120;&#116;&#123;&#77;&#101;&#100;&#105;&#97;&#110;&#97;&#125;&#32;&#61;&#32;&#120;&#95;&#123;&#92;&#102;&#114;&#97;&#99;&#123;&#110;&#43;&#49;&#125;&#123;&#50;&#125;&#125;" title="Rendered by QuickLaTeX.com" height="23" width="125" style="vertical-align: -11px;"/></li>



<li>Se <img loading="lazy" decoding="async" src="https://renor.it/wp-content/ql-cache/quicklatex.com-b170995d512c659d8668b4e42e1fef6b_l3.png" class="ql-img-inline-formula quicklatex-auto-format" alt="&#110;" title="Rendered by QuickLaTeX.com" height="8" width="11" style="vertical-align: 0px;"/> è pari, la mediana è la media aritmetica dei due elementi centrali: <br><img loading="lazy" decoding="async" src="https://renor.it/wp-content/ql-cache/quicklatex.com-91f6e57fe8ee5c52baa255e5225e1cd1_l3.png" class="ql-img-inline-formula quicklatex-auto-format" alt="&#92;&#116;&#101;&#120;&#116;&#123;&#77;&#101;&#100;&#105;&#97;&#110;&#97;&#125;&#32;&#61;&#32;&#92;&#102;&#114;&#97;&#99;&#123;&#120;&#95;&#123;&#92;&#102;&#114;&#97;&#99;&#123;&#110;&#125;&#123;&#50;&#125;&#125;&#32;&#43;&#32;&#120;&#95;&#123;&#92;&#102;&#114;&#97;&#99;&#123;&#110;&#125;&#123;&#50;&#125;&#43;&#49;&#125;&#125;&#123;&#50;&#125;" title="Rendered by QuickLaTeX.com" height="28" width="158" style="vertical-align: -6px;"/></li>
</ul>



<p class="wp-block-paragraph">A differenza della media aritmetica, la mediana è robusta rispetto agli outlier, poiché dipende solo dall&#8217;ordinamento dei dati e non dalla loro ampiezza. </p>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#1E1E1E"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" data-code=" /**
     * Calculates the median (50th percentile) of the dataset.
     *
     * @return float The median value.
     */
    public function median(): float
    {
        // Clone and sort the dataset to avoid mutating the original array
        $sorted = $this-&gt;data;
        sort($sorted, SORT_NUMERIC);

        $count = count($sorted);
        $mid   = intdiv($count, 2);

        // If the count is odd, return the middle value
        if ($count % 2 === 1) {
            return (float) $sorted[$mid];
        }

        // If even, return the average of the two central values
        return ($sorted[$mid - 1] + $sorted[$mid]) / 2.0;
    }" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"><span style="color: #D4D4D4"> </span><span style="color: #6A9955">/**</span></span>
<span class="line"><span style="color: #6A9955">     * Calculates the median (50th percentile) of the dataset.</span></span>
<span class="line"><span style="color: #6A9955">     *</span></span>
<span class="line"><span style="color: #6A9955">     * </span><span style="color: #569CD6">@return</span><span style="color: #6A9955"> </span><span style="color: #569CD6">float</span><span style="color: #6A9955"> The median value.</span></span>
<span class="line"><span style="color: #6A9955">     */</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #569CD6">public</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">function</span><span style="color: #D4D4D4"> </span><span style="color: #DCDCAA">median</span><span style="color: #D4D4D4">(): </span><span style="color: #569CD6">float</span></span>
<span class="line"><span style="color: #D4D4D4">    {</span></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #6A9955">// Clone and sort the dataset to avoid mutating the original array</span></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #9CDCFE">$sorted</span><span style="color: #D4D4D4"> = </span><span style="color: #569CD6">$this</span><span style="color: #D4D4D4">-&gt;</span><span style="color: #9CDCFE">data</span><span style="color: #D4D4D4">;</span></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #DCDCAA">sort</span><span style="color: #D4D4D4">(</span><span style="color: #9CDCFE">$sorted</span><span style="color: #D4D4D4">, SORT_NUMERIC);</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #9CDCFE">$count</span><span style="color: #D4D4D4"> = </span><span style="color: #DCDCAA">count</span><span style="color: #D4D4D4">(</span><span style="color: #9CDCFE">$sorted</span><span style="color: #D4D4D4">);</span></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #9CDCFE">$mid</span><span style="color: #D4D4D4">   = </span><span style="color: #DCDCAA">intdiv</span><span style="color: #D4D4D4">(</span><span style="color: #9CDCFE">$count</span><span style="color: #D4D4D4">, </span><span style="color: #B5CEA8">2</span><span style="color: #D4D4D4">);</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #6A9955">// If the count is odd, return the middle value</span></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #C586C0">if</span><span style="color: #D4D4D4"> (</span><span style="color: #9CDCFE">$count</span><span style="color: #D4D4D4"> % </span><span style="color: #B5CEA8">2</span><span style="color: #D4D4D4"> === </span><span style="color: #B5CEA8">1</span><span style="color: #D4D4D4">) {</span></span>
<span class="line"><span style="color: #D4D4D4">            </span><span style="color: #C586C0">return</span><span style="color: #D4D4D4"> (</span><span style="color: #569CD6">float</span><span style="color: #D4D4D4">) </span><span style="color: #9CDCFE">$sorted</span><span style="color: #D4D4D4">[</span><span style="color: #9CDCFE">$mid</span><span style="color: #D4D4D4">];</span></span>
<span class="line"><span style="color: #D4D4D4">        }</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #6A9955">// If even, return the average of the two central values</span></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #C586C0">return</span><span style="color: #D4D4D4"> (</span><span style="color: #9CDCFE">$sorted</span><span style="color: #D4D4D4">[</span><span style="color: #9CDCFE">$mid</span><span style="color: #D4D4D4"> - </span><span style="color: #B5CEA8">1</span><span style="color: #D4D4D4">] + </span><span style="color: #9CDCFE">$sorted</span><span style="color: #D4D4D4">[</span><span style="color: #9CDCFE">$mid</span><span style="color: #D4D4D4">]) / </span><span style="color: #B5CEA8">2.0</span><span style="color: #D4D4D4">;</span></span>
<span class="line"><span style="color: #D4D4D4">    }</span></span></code></pre></div>



<p class="wp-block-paragraph">In questo metodo recupero i dati e li ordino. Otteniamo la dimensione e ricarivamo l&#8217;indice centrale con la divisione intera. Ad esempio se abbiamo 7 elementi, <code>intdiv(7,2)</code> restituisce 3, che corrisponde alla quarta posizione (ricorda che gli array in PHP sono zero-based!).  Se il numero di valori è dispari, esiste un unico elemento perfettamente centrale e lo restituisce. In caso di numerosità pari, invece non c&#8217;è un solo valore centrale, ce ne sono due, quello in posizione <code>$mid - 1</code> e quello in posizione <code>$mid</code>. La mediana per definizione è la media aritmetica di questi due valori. Sommiamo quindi i centrali e dividiamo per 2.0 (con la notazione decimale per forzare la divisione in virgola mobile) ottenendo a sua volta un risultato float. In questo modo il metodo restituisce il cinquantesimo percentile del campione senza modificare il dataset originario e rispettando la definizione statistica sia per serie di lunghezza dispari che pari. </p>



<h2 class="wp-block-heading">Moda</h2>



<p class="wp-block-paragraph">Dopo media e mediana, il terzo indicatore classicamente più utilizzato della statistica descrittiva è la moda, ossia il valore, o i valori, che ricorrono più spesso all&#8217;interno di un insieme di osservazioni. se denotiamo con <img loading="lazy" decoding="async" src="https://renor.it/wp-content/ql-cache/quicklatex.com-a7ee323bc5a3f73ad5e066b13bed5504_l3.png" class="ql-img-inline-formula quicklatex-auto-format" alt="&#102;&#40;&#120;&#41;" title="Rendered by QuickLaTeX.com" height="19" width="34" style="vertical-align: -5px;"/> la frequenza assoluta di un valore <img loading="lazy" decoding="async" src="https://renor.it/wp-content/ql-cache/quicklatex.com-ede05c264bba0eda080918aaa09c4658_l3.png" class="ql-img-inline-formula quicklatex-auto-format" alt="&#120;" title="Rendered by QuickLaTeX.com" height="8" width="10" style="vertical-align: 0px;"/> nel campione, la moda si ottiene come</p>



<p class="wp-block-paragraph"><img loading="lazy" decoding="async" src="https://renor.it/wp-content/ql-cache/quicklatex.com-2fa8242aeb4fa25a67e1f100b8cdf195_l3.png" class="ql-img-inline-formula quicklatex-auto-format" alt="&#92;&#116;&#101;&#120;&#116;&#123;&#77;&#111;&#100;&#97;&#125;&#32;&#61;&#32;&#92;&#111;&#112;&#101;&#114;&#97;&#116;&#111;&#114;&#110;&#97;&#109;&#101;&#42;&#123;&#97;&#114;&#103;&#92;&#44;&#109;&#97;&#120;&#125;&#95;&#123;&#120;&#125;&#92;&#59;&#32;&#102;&#40;&#120;&#41;" title="Rendered by QuickLaTeX.com" height="19" width="179" style="vertical-align: -5px;"/>.</p>



<p class="wp-block-paragraph">Possiamo distinguere per la serie di valori in ingresso:</p>



<ul class="wp-block-list">
<li>Serie unimodale quando un solo valore ha la frequenza massima</li>



<li>Serie multimodale quando due o più valori condividono la frequenza massima</li>



<li>Serie senza moda quanto tutti i valori della serie compaiono all&#8217;interno della stessa una sola volta</li>
</ul>



<p class="wp-block-paragraph">La moda è particolarmente utile quando i dati sono categorici o quando si vuole evidenziare la concentrazione attorno a determinati valori interi. A differenza di media e mediana non misura la posizione centrale ma il valore o i valori che si ripetono maggiormente nella serie. Non a caso quando un capo d&#8217;abbigliamento è di moda è perché questo, rispetto ad altri capi d&#8217;abbigliamento in una serie di vendite, risulta quello più venduto e quindi &#8220;quello che va più di moda&#8221;. </p>



<p class="wp-block-paragraph">Aggiungiamo quindi il metodo alla nostra classe:</p>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#1E1E1E"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" data-code="/**
 * Returns the mode(s) of the dataset.
 *
 * If the dataset is multimodal, an array with all modal values is returned.
 * If every value occurs only once, an empty array is returned (no mode).
 *
 * @return float[] list of modal values
 */
public function mode(): array
{
    // Build a frequency table: value =&gt; occurrences
    $frequencies = array_count_values($this-&gt;data);

    // Determine the highest frequency
    $maxFrequency = max($frequencies);

    // If every value appears only once, there is no mode
    if ($maxFrequency === 1) {
        return [];
    }

    // Collect all values that share the highest frequency
    $modes = [];
    foreach ($frequencies as $value =&gt; $count) {
        if ($count === $maxFrequency) {
            // Cast to float so that return type is consistent
            $modes[] = (float) $value;
        }
    }

    sort($modes, SORT_NUMERIC); // return modes in ascending order
    return $modes;
}" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"><span style="color: #6A9955">/**</span></span>
<span class="line"><span style="color: #6A9955"> * Returns the mode(s) of the dataset.</span></span>
<span class="line"><span style="color: #6A9955"> *</span></span>
<span class="line"><span style="color: #6A9955"> * If the dataset is multimodal, an array with all modal values is returned.</span></span>
<span class="line"><span style="color: #6A9955"> * If every value occurs only once, an empty array is returned (no mode).</span></span>
<span class="line"><span style="color: #6A9955"> *</span></span>
<span class="line"><span style="color: #6A9955"> * </span><span style="color: #569CD6">@return</span><span style="color: #6A9955"> </span><span style="color: #569CD6">float[]</span><span style="color: #6A9955"> list of modal values</span></span>
<span class="line"><span style="color: #6A9955"> */</span></span>
<span class="line"><span style="color: #569CD6">public</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">function</span><span style="color: #D4D4D4"> </span><span style="color: #DCDCAA">mode</span><span style="color: #D4D4D4">(): </span><span style="color: #569CD6">array</span></span>
<span class="line"><span style="color: #D4D4D4">{</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #6A9955">// Build a frequency table: value =&gt; occurrences</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #9CDCFE">$frequencies</span><span style="color: #D4D4D4"> = </span><span style="color: #DCDCAA">array_count_values</span><span style="color: #D4D4D4">(</span><span style="color: #569CD6">$this</span><span style="color: #D4D4D4">-&gt;</span><span style="color: #9CDCFE">data</span><span style="color: #D4D4D4">);</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #6A9955">// Determine the highest frequency</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #9CDCFE">$maxFrequency</span><span style="color: #D4D4D4"> = </span><span style="color: #DCDCAA">max</span><span style="color: #D4D4D4">(</span><span style="color: #9CDCFE">$frequencies</span><span style="color: #D4D4D4">);</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #6A9955">// If every value appears only once, there is no mode</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #C586C0">if</span><span style="color: #D4D4D4"> (</span><span style="color: #9CDCFE">$maxFrequency</span><span style="color: #D4D4D4"> === </span><span style="color: #B5CEA8">1</span><span style="color: #D4D4D4">) {</span></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #C586C0">return</span><span style="color: #D4D4D4"> [];</span></span>
<span class="line"><span style="color: #D4D4D4">    }</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #6A9955">// Collect all values that share the highest frequency</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #9CDCFE">$modes</span><span style="color: #D4D4D4"> = [];</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #C586C0">foreach</span><span style="color: #D4D4D4"> (</span><span style="color: #9CDCFE">$frequencies</span><span style="color: #D4D4D4"> as </span><span style="color: #9CDCFE">$value</span><span style="color: #D4D4D4"> =&gt; </span><span style="color: #9CDCFE">$count</span><span style="color: #D4D4D4">) {</span></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #C586C0">if</span><span style="color: #D4D4D4"> (</span><span style="color: #9CDCFE">$count</span><span style="color: #D4D4D4"> === </span><span style="color: #9CDCFE">$maxFrequency</span><span style="color: #D4D4D4">) {</span></span>
<span class="line"><span style="color: #D4D4D4">            </span><span style="color: #6A9955">// Cast to float so that return type is consistent</span></span>
<span class="line"><span style="color: #D4D4D4">            </span><span style="color: #9CDCFE">$modes</span><span style="color: #D4D4D4">[] = (</span><span style="color: #569CD6">float</span><span style="color: #D4D4D4">) </span><span style="color: #9CDCFE">$value</span><span style="color: #D4D4D4">;</span></span>
<span class="line"><span style="color: #D4D4D4">        }</span></span>
<span class="line"><span style="color: #D4D4D4">    }</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #DCDCAA">sort</span><span style="color: #D4D4D4">(</span><span style="color: #9CDCFE">$modes</span><span style="color: #D4D4D4">, SORT_NUMERIC); </span><span style="color: #6A9955">// return modes in ascending order</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #C586C0">return</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">$modes</span><span style="color: #D4D4D4">;</span></span>
<span class="line"><span style="color: #D4D4D4">}</span></span></code></pre></div>



<p class="wp-block-paragraph"><br><br><code>array_count_values()</code> scorre l’intero dataset e restituisce un array associativo in cui la <strong>chiave</strong> è il valore osservato e il <strong>valore</strong> è quante volte ricorre. È un modo rapido per calcolare <img loading="lazy" decoding="async" src="https://renor.it/wp-content/ql-cache/quicklatex.com-a7ee323bc5a3f73ad5e066b13bed5504_l3.png" class="ql-img-inline-formula quicklatex-auto-format" alt="&#102;&#40;&#120;&#41;" title="Rendered by QuickLaTeX.com" height="19" width="34" style="vertical-align: -5px;"/> per ogni <img loading="lazy" decoding="async" src="https://renor.it/wp-content/ql-cache/quicklatex.com-ede05c264bba0eda080918aaa09c4658_l3.png" class="ql-img-inline-formula quicklatex-auto-format" alt="&#120;" title="Rendered by QuickLaTeX.com" height="8" width="10" style="vertical-align: 0px;"/>.<br>Con <code>max($frequencies)</code> otteniamo il numero di occorrenze più alto presente nella tabella; è il valore di <img loading="lazy" decoding="async" src="https://renor.it/wp-content/ql-cache/quicklatex.com-1ccf759ba917b35db6276661cda96893_l3.png" class="ql-img-inline-formula quicklatex-auto-format" alt="&#92;&#109;&#97;&#120;&#32;&#102;&#40;&#120;&#41;" title="Rendered by QuickLaTeX.com" height="19" width="70" style="vertical-align: -5px;"/> nella definizione matematica.<br>Se la frequenza massima è 1, significa che ogni osservazione è unica. In tal caso il metodo restituisce un array vuoto per indicare che non esiste alcun valore modale.<br>Si itera sulla tabella delle frequenze: per ogni chiave il cui conteggio eguaglia la frequenza massima, si aggiunge quel valore (cast a float) all’array <code>$modes</code>. In questo modo vengono inclusi <strong>tutti</strong> i valori modali in caso di multimodalità.<br>Prima di restituire il risultato, <code>sort($modes, SORT_NUMERIC)</code> assicura che le mode siano ordinate in senso crescente, rendendo più prevedibile l’output.</p>



<p class="wp-block-paragraph">In questo modo abbiamo coperto tutti i possibili scenari: unimodali, multimodali e senza moda. </p>



<h2 class="wp-block-heading">Media geometrica</h2>



<p class="wp-block-paragraph">La <strong>media geometrica</strong> è la misura di tendenza centrale più adatta quando i dati rappresentano <em>tassi di crescita</em> o <em>rapporti</em> (per esempio rendimenti percentuali, indici di variazione, scale logaritmiche).</p>



<p class="wp-block-paragraph">Data una serie di <img loading="lazy" decoding="async" src="https://renor.it/wp-content/ql-cache/quicklatex.com-b170995d512c659d8668b4e42e1fef6b_l3.png" class="ql-img-inline-formula quicklatex-auto-format" alt="&#110;" title="Rendered by QuickLaTeX.com" height="8" width="11" style="vertical-align: 0px;"/> valori <strong>tutti strettamente positivi</strong> <img loading="lazy" decoding="async" src="https://renor.it/wp-content/ql-cache/quicklatex.com-5e8319f54f72e7dac2238515c1499b27_l3.png" class="ql-img-inline-formula quicklatex-auto-format" alt="&#120;&#95;&#49;&#44;&#32;&#120;&#95;&#50;&#44;&#32;&#92;&#100;&#111;&#116;&#115;&#44;&#32;&#120;&#95;&#110;" title="Rendered by QuickLaTeX.com" height="12" width="101" style="vertical-align: -4px;"/>, la media geometrica <img loading="lazy" decoding="async" src="https://renor.it/wp-content/ql-cache/quicklatex.com-30a79c32f18567063fe44716929e7ced_l3.png" class="ql-img-inline-formula quicklatex-auto-format" alt="&#71;" title="Rendered by QuickLaTeX.com" height="12" width="14" style="vertical-align: 0px;"/> si definisce come:</p>



<p class="wp-block-paragraph"><br><img loading="lazy" decoding="async" src="https://renor.it/wp-content/ql-cache/quicklatex.com-a4742ffe66183a651acae6a09c623c28_l3.png" class="ql-img-inline-formula quicklatex-auto-format" alt="&#71;&#32;&#92;&#59;&#61;&#92;&#59;&#32;&#92;&#66;&#105;&#103;&#108;&#40;&#32;&#92;&#112;&#114;&#111;&#100;&#95;&#123;&#105;&#61;&#49;&#125;&#94;&#123;&#110;&#125;&#32;&#120;&#95;&#105;&#32;&#92;&#66;&#105;&#103;&#114;&#41;&#94;&#123;&#92;&#102;&#114;&#97;&#99;&#123;&#49;&#125;&#123;&#110;&#125;&#125;" title="Rendered by QuickLaTeX.com" height="39" width="137" style="vertical-align: -11px;"/></p>



<p class="wp-block-paragraph">oppure in forma logaritmica più stabile numericamente</p>



<p class="wp-block-paragraph"><img loading="lazy" decoding="async" src="https://renor.it/wp-content/ql-cache/quicklatex.com-d61959aa5fbed45f159915591eb7e023_l3.png" class="ql-img-inline-formula quicklatex-auto-format" alt="&#92;&#108;&#110;&#32;&#71;&#32;&#92;&#59;&#61;&#92;&#59;&#32;&#92;&#102;&#114;&#97;&#99;&#123;&#49;&#125;&#123;&#110;&#125;&#32;&#92;&#115;&#117;&#109;&#95;&#123;&#105;&#61;&#49;&#125;&#94;&#123;&#110;&#125;&#32;&#92;&#108;&#110;&#32;&#120;&#95;&#105;" title="Rendered by QuickLaTeX.com" height="22" width="158" style="vertical-align: -6px;"/>.</p>



<p class="wp-block-paragraph"><br>Questa quantità corrisponde al fattore di crescita “medio” che, applicato n volte in sequenza, produce lo stesso risultato del prodotto reale dei valori.</p>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#1E1E1E"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" data-code="/**
 * Calculates the geometric mean of the dataset.
 *
 * @throws DomainException If any value is zero or negative.
 * @return float The geometric mean.
 */
public function geometricMean(): float
{
    // The geometric mean is defined only for strictly positive numbers.
    foreach ($this-&gt;data as $value) {
        if ($value &lt;= 0) {
            throw new DomainException('Geometric mean requires all values to be greater than zero.');
        }
    }

    // Use logarithms for numerical stability: exp( (1/n) * sum(log(x_i)) )
    $logSum = array_sum(array_map('log', $this-&gt;data));
    return exp($logSum / count($this-&gt;data));
}" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"><span style="color: #6A9955">/**</span></span>
<span class="line"><span style="color: #6A9955"> * Calculates the geometric mean of the dataset.</span></span>
<span class="line"><span style="color: #6A9955"> *</span></span>
<span class="line"><span style="color: #6A9955"> * </span><span style="color: #569CD6">@throws</span><span style="color: #6A9955"> </span><span style="color: #4EC9B0">DomainException</span><span style="color: #6A9955"> If any value is zero or negative.</span></span>
<span class="line"><span style="color: #6A9955"> * </span><span style="color: #569CD6">@return</span><span style="color: #6A9955"> </span><span style="color: #569CD6">float</span><span style="color: #6A9955"> The geometric mean.</span></span>
<span class="line"><span style="color: #6A9955"> */</span></span>
<span class="line"><span style="color: #569CD6">public</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">function</span><span style="color: #D4D4D4"> </span><span style="color: #DCDCAA">geometricMean</span><span style="color: #D4D4D4">(): </span><span style="color: #569CD6">float</span></span>
<span class="line"><span style="color: #D4D4D4">{</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #6A9955">// The geometric mean is defined only for strictly positive numbers.</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #C586C0">foreach</span><span style="color: #D4D4D4"> (</span><span style="color: #569CD6">$this</span><span style="color: #D4D4D4">-&gt;</span><span style="color: #9CDCFE">data</span><span style="color: #D4D4D4"> as </span><span style="color: #9CDCFE">$value</span><span style="color: #D4D4D4">) {</span></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #C586C0">if</span><span style="color: #D4D4D4"> (</span><span style="color: #9CDCFE">$value</span><span style="color: #D4D4D4"> &lt;= </span><span style="color: #B5CEA8">0</span><span style="color: #D4D4D4">) {</span></span>
<span class="line"><span style="color: #D4D4D4">            </span><span style="color: #C586C0">throw</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">new</span><span style="color: #D4D4D4"> </span><span style="color: #4EC9B0">DomainException</span><span style="color: #D4D4D4">(</span><span style="color: #CE9178">&#39;Geometric mean requires all values to be greater than zero.&#39;</span><span style="color: #D4D4D4">);</span></span>
<span class="line"><span style="color: #D4D4D4">        }</span></span>
<span class="line"><span style="color: #D4D4D4">    }</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #6A9955">// Use logarithms for numerical stability: exp( (1/n) * sum(log(x_i)) )</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #9CDCFE">$logSum</span><span style="color: #D4D4D4"> = </span><span style="color: #DCDCAA">array_sum</span><span style="color: #D4D4D4">(</span><span style="color: #DCDCAA">array_map</span><span style="color: #D4D4D4">(</span><span style="color: #CE9178">&#39;log&#39;</span><span style="color: #D4D4D4">, </span><span style="color: #569CD6">$this</span><span style="color: #D4D4D4">-&gt;</span><span style="color: #9CDCFE">data</span><span style="color: #D4D4D4">));</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #C586C0">return</span><span style="color: #D4D4D4"> </span><span style="color: #DCDCAA">exp</span><span style="color: #D4D4D4">(</span><span style="color: #9CDCFE">$logSum</span><span style="color: #D4D4D4"> / </span><span style="color: #DCDCAA">count</span><span style="color: #D4D4D4">(</span><span style="color: #569CD6">$this</span><span style="color: #D4D4D4">-&gt;</span><span style="color: #9CDCFE">data</span><span style="color: #D4D4D4">));</span></span>
<span class="line"><span style="color: #D4D4D4">}</span></span></code></pre></div>



<p class="wp-block-paragraph"><br><br>Poiché la media geometrica è definita solo per numeri positivi, il metodo scorre il dataset e lancia una DomainException se trova valori ≤ 0. Questo previene risultati matematicamente scorretti (o complessi).<br>Invece di calcolare direttamente il prodotto (che potrebbe facilmente andare in overflow), convertiamo ogni valore con <code>log()</code>, sommiamo i logaritmi e dividiamo per <img loading="lazy" decoding="async" src="https://renor.it/wp-content/ql-cache/quicklatex.com-b170995d512c659d8668b4e42e1fef6b_l3.png" class="ql-img-inline-formula quicklatex-auto-format" alt="&#110;" title="Rendered by QuickLaTeX.com" height="8" width="11" style="vertical-align: 0px;"/>. In base alle proprietà dei logaritmi: <br><img loading="lazy" decoding="async" src="https://renor.it/wp-content/ql-cache/quicklatex.com-43f802e186e975abe5f7cfa92e0d7040_l3.png" class="ql-img-inline-formula quicklatex-auto-format" alt="&#92;&#108;&#110;&#92;&#33;&#92;&#66;&#105;&#103;&#108;&#40;&#92;&#112;&#114;&#111;&#100;&#32;&#120;&#95;&#105;&#92;&#66;&#105;&#103;&#114;&#41;&#32;&#92;&#59;&#61;&#92;&#59;&#32;&#92;&#115;&#117;&#109;&#32;&#92;&#108;&#110;&#32;&#120;&#95;&#105;" title="Rendered by QuickLaTeX.com" height="32" width="156" style="vertical-align: -11px;"/><br><br>Applicando <code>exp()</code> al valore medio dei logaritmi otteniamo la media geometrica.<br><img loading="lazy" decoding="async" src="https://renor.it/wp-content/ql-cache/quicklatex.com-bfbde60fff002baebb36779f76f72332_l3.png" class="ql-img-inline-formula quicklatex-auto-format" alt="&#71;&#32;&#92;&#59;&#61;&#92;&#59;&#32;&#92;&#101;&#120;&#112;&#92;&#33;&#92;&#66;&#105;&#103;&#108;&#40;&#92;&#116;&#102;&#114;&#97;&#99;&#123;&#49;&#125;&#123;&#110;&#125;&#92;&#115;&#117;&#109;&#32;&#92;&#108;&#110;&#32;&#120;&#95;&#105;&#92;&#66;&#105;&#103;&#114;&#41;" title="Rendered by QuickLaTeX.com" height="32" width="160" style="vertical-align: -11px;"/></p>



<h2 class="wp-block-heading">Media armonica</h2>



<p class="wp-block-paragraph">La <strong>media armonica</strong> è la misura di tendenza centrale più indicata quando i dati rappresentano <strong>velocità, rapporti o frazioni</strong>: per esempio km / h percorsi a diversi ritmi, costo medio per unità o rendimento medio di investimenti calcolato come “quote per euro”.</p>



<p class="wp-block-paragraph">Data una serie di <img loading="lazy" decoding="async" src="https://renor.it/wp-content/ql-cache/quicklatex.com-b170995d512c659d8668b4e42e1fef6b_l3.png" class="ql-img-inline-formula quicklatex-auto-format" alt="&#110;" title="Rendered by QuickLaTeX.com" height="8" width="11" style="vertical-align: 0px;"/> valori positivi <img loading="lazy" decoding="async" src="https://renor.it/wp-content/ql-cache/quicklatex.com-5e8319f54f72e7dac2238515c1499b27_l3.png" class="ql-img-inline-formula quicklatex-auto-format" alt="&#120;&#95;&#49;&#44;&#32;&#120;&#95;&#50;&#44;&#32;&#92;&#100;&#111;&#116;&#115;&#44;&#32;&#120;&#95;&#110;" title="Rendered by QuickLaTeX.com" height="12" width="101" style="vertical-align: -4px;"/> (nessun valore può essere zero, perché apparirebbe al denominatore), la media armonica <img loading="lazy" decoding="async" src="https://renor.it/wp-content/ql-cache/quicklatex.com-379db1fc1f84b7ce56b92463183097f9_l3.png" class="ql-img-inline-formula quicklatex-auto-format" alt="&#72;" title="Rendered by QuickLaTeX.com" height="12" width="16" style="vertical-align: 0px;"/> si definisce come:<br><br><img loading="lazy" decoding="async" src="https://renor.it/wp-content/ql-cache/quicklatex.com-3d6ce62f9aca45ea9d0e009d4e105ee4_l3.png" class="ql-img-inline-formula quicklatex-auto-format" alt="&#72;&#32;&#92;&#59;&#61;&#92;&#59;&#32;&#92;&#102;&#114;&#97;&#99;&#123;&#110;&#125;&#123;&#92;&#100;&#105;&#115;&#112;&#108;&#97;&#121;&#115;&#116;&#121;&#108;&#101;&#92;&#115;&#117;&#109;&#95;&#123;&#105;&#61;&#49;&#125;&#94;&#123;&#110;&#125;&#32;&#92;&#102;&#114;&#97;&#99;&#123;&#49;&#125;&#123;&#120;&#95;&#105;&#125;&#125;" title="Rendered by QuickLaTeX.com" height="60" width="101" style="vertical-align: -47px;"/></p>



<p class="wp-block-paragraph">In altre parole si calcola l’inverso della <strong>media aritmetica degli inversi</strong>. Rispetto alla media aritmetica, la media armonica <strong>pesa di più i valori piccoli</strong>: è quindi preziosa quando si desidera penalizzare fortemente le prestazioni peggiori (es.: il tempo medio per percorrere un chilometro su più tratte di diversa velocità).</p>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#1E1E1E"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" data-code="/**
 * Calculates the harmonic mean of the dataset.
 *
 * @throws DomainException If any value is zero or negative.
 * @return float The harmonic mean.
 */
public function harmonicMean(): float
{
    // Harmonic mean is defined only for strictly positive numbers.
    foreach ($this-&gt;data as $value) {
        if ($value &lt;= 0) {
            throw new DomainException('Harmonic mean requires all values to be greater than zero.');
        }
    }

    $inverseSum = array_sum(array_map(
        static fn (float $v): float =&gt; 1.0 / $v,
        $this-&gt;data
    ));

    return count($this-&gt;data) / $inverseSum;
}" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"><span style="color: #6A9955">/**</span></span>
<span class="line"><span style="color: #6A9955"> * Calculates the harmonic mean of the dataset.</span></span>
<span class="line"><span style="color: #6A9955"> *</span></span>
<span class="line"><span style="color: #6A9955"> * </span><span style="color: #569CD6">@throws</span><span style="color: #6A9955"> </span><span style="color: #4EC9B0">DomainException</span><span style="color: #6A9955"> If any value is zero or negative.</span></span>
<span class="line"><span style="color: #6A9955"> * </span><span style="color: #569CD6">@return</span><span style="color: #6A9955"> </span><span style="color: #569CD6">float</span><span style="color: #6A9955"> The harmonic mean.</span></span>
<span class="line"><span style="color: #6A9955"> */</span></span>
<span class="line"><span style="color: #569CD6">public</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">function</span><span style="color: #D4D4D4"> </span><span style="color: #DCDCAA">harmonicMean</span><span style="color: #D4D4D4">(): </span><span style="color: #569CD6">float</span></span>
<span class="line"><span style="color: #D4D4D4">{</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #6A9955">// Harmonic mean is defined only for strictly positive numbers.</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #C586C0">foreach</span><span style="color: #D4D4D4"> (</span><span style="color: #569CD6">$this</span><span style="color: #D4D4D4">-&gt;</span><span style="color: #9CDCFE">data</span><span style="color: #D4D4D4"> as </span><span style="color: #9CDCFE">$value</span><span style="color: #D4D4D4">) {</span></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #C586C0">if</span><span style="color: #D4D4D4"> (</span><span style="color: #9CDCFE">$value</span><span style="color: #D4D4D4"> &lt;= </span><span style="color: #B5CEA8">0</span><span style="color: #D4D4D4">) {</span></span>
<span class="line"><span style="color: #D4D4D4">            </span><span style="color: #C586C0">throw</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">new</span><span style="color: #D4D4D4"> </span><span style="color: #4EC9B0">DomainException</span><span style="color: #D4D4D4">(</span><span style="color: #CE9178">&#39;Harmonic mean requires all values to be greater than zero.&#39;</span><span style="color: #D4D4D4">);</span></span>
<span class="line"><span style="color: #D4D4D4">        }</span></span>
<span class="line"><span style="color: #D4D4D4">    }</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #9CDCFE">$inverseSum</span><span style="color: #D4D4D4"> = </span><span style="color: #DCDCAA">array_sum</span><span style="color: #D4D4D4">(</span><span style="color: #DCDCAA">array_map</span><span style="color: #D4D4D4">(</span></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #569CD6">static</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">fn</span><span style="color: #D4D4D4"> (</span><span style="color: #569CD6">float</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">$v</span><span style="color: #D4D4D4">): </span><span style="color: #569CD6">float</span><span style="color: #D4D4D4"> =&gt; </span><span style="color: #B5CEA8">1.0</span><span style="color: #D4D4D4"> / </span><span style="color: #9CDCFE">$v</span><span style="color: #D4D4D4">,</span></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #569CD6">$this</span><span style="color: #D4D4D4">-&gt;</span><span style="color: #9CDCFE">data</span></span>
<span class="line"><span style="color: #D4D4D4">    ));</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #C586C0">return</span><span style="color: #D4D4D4"> </span><span style="color: #DCDCAA">count</span><span style="color: #D4D4D4">(</span><span style="color: #569CD6">$this</span><span style="color: #D4D4D4">-&gt;</span><span style="color: #9CDCFE">data</span><span style="color: #D4D4D4">) / </span><span style="color: #9CDCFE">$inverseSum</span><span style="color: #D4D4D4">;</span></span>
<span class="line"><span style="color: #D4D4D4">}</span></span></code></pre></div>



<p class="wp-block-paragraph">Per prima cosa si effettua un controllo di dominio, qualunque valore maggiore o uguale a zero genera una DomainException, altrimenti il risultato non sarebbe definitivo o diverrebbe infinito. Poi si effettua una somma degli inversi: <code>array_map()</code> calcola l&#8217;inverso di ogni elemento, <code>array_sum()</code> li somma. <br>La formula diretta divide il numero di osservazioni <img loading="lazy" decoding="async" src="https://renor.it/wp-content/ql-cache/quicklatex.com-b170995d512c659d8668b4e42e1fef6b_l3.png" class="ql-img-inline-formula quicklatex-auto-format" alt="&#110;" title="Rendered by QuickLaTeX.com" height="8" width="11" style="vertical-align: 0px;"/> per la somma ottenuta, secondo la definizione matematica. </p>



<h2 class="wp-block-heading">Troncamento della media (o media troncata)</h2>



<p class="wp-block-paragraph">Quando un campione contiene <strong>outlier</strong> estremi che rischiano di distorcere la media aritmetica, una soluzione elegante è la <strong>media troncata</strong> (o <em>trimmed mean</em>).</p>



<p class="wp-block-paragraph">Si sceglie una percentuale <img loading="lazy" decoding="async" src="https://renor.it/wp-content/ql-cache/quicklatex.com-3bf85f1087e9fbed3a319341134ac1a2_l3.png" class="ql-img-inline-formula quicklatex-auto-format" alt="&#112;" title="Rendered by QuickLaTeX.com" height="12" width="10" style="vertical-align: -4px;"/> % (tipicamente 5 % oppure 10 %), si ordina il campione e si <strong>scartano</strong> le prime <img loading="lazy" decoding="async" src="https://renor.it/wp-content/ql-cache/quicklatex.com-3422b6bb5c160593658b7c39425d9880_l3.png" class="ql-img-inline-formula quicklatex-auto-format" alt="&#107;" title="Rendered by QuickLaTeX.com" height="12" width="9" style="vertical-align: 0px;"/> osservazioni più piccole e le ultime <img loading="lazy" decoding="async" src="https://renor.it/wp-content/ql-cache/quicklatex.com-3422b6bb5c160593658b7c39425d9880_l3.png" class="ql-img-inline-formula quicklatex-auto-format" alt="&#107;" title="Rendered by QuickLaTeX.com" height="12" width="9" style="vertical-align: 0px;"/> più grandi, dove</p>



<p class="wp-block-paragraph"><img loading="lazy" decoding="async" src="https://renor.it/wp-content/ql-cache/quicklatex.com-1c8bb9d76cc219191a1ff6a56a92421a_l3.png" class="ql-img-inline-formula quicklatex-auto-format" alt="&#92;&#98;&#97;&#114;&#123;&#120;&#125;&#95;&#123;&#92;&#116;&#101;&#120;&#116;&#123;&#116;&#114;&#105;&#109;&#125;&#125;&#32;&#92;&#59;&#61;&#92;&#59;&#32;&#92;&#102;&#114;&#97;&#99;&#123;&#49;&#125;&#123;&#92;&#44;&#110;&#45;&#50;&#107;&#92;&#44;&#125;&#32;&#92;&#115;&#117;&#109;&#95;&#123;&#105;&#61;&#107;&#43;&#49;&#125;&#94;&#123;&#92;&#44;&#110;&#45;&#107;&#125;&#32;&#120;&#95;&#123;&#40;&#105;&#41;&#125;" title="Rendered by QuickLaTeX.com" height="25" width="202" style="vertical-align: -8px;"/>.<br><br>In questo modo si ottiene una misura di tendenza centrale <strong>più robusta</strong> della media aritmetica ma meno drastica della mediana.</p>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#1E1E1E"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" data-code="/**
 * Calculates the trimmed mean of the dataset.
 *
 * @param float $percent Percentage (0–50) of data to trim at each tail.
 * @throws DomainException If $percent is out of range or removes all data.
 * @return float The trimmed mean.
 */
public function trimmedMean(float $percent): float
{
    if ($percent &lt; 0.0 || $percent &gt;= 50.0) {
        throw new DomainException('Percent must be in the range 0 &lt;= p &lt; 50.');
    }

    $count = count($this-&gt;data);
    if ($count &lt; 3) {
        // Too few values to trim meaningfully; fall back to arithmetic mean
        return $this-&gt;mean();
    }

    // Clone and sort to preserve original order
    $sorted = $this-&gt;data;
    sort($sorted, SORT_NUMERIC);

    // Number of elements to trim from each end
    $k = (int) floor($count * $percent / 100.0);

    // Ensure at least one value remains
    if ($k * 2 &gt;= $count) {
        throw new DomainException('Trim percentage removes all data.');
    }

    $trimmed = array_slice($sorted, $k, $count - 2 * $k);

    return array_sum($trimmed) / count($trimmed);
}" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"><span style="color: #6A9955">/**</span></span>
<span class="line"><span style="color: #6A9955"> * Calculates the trimmed mean of the dataset.</span></span>
<span class="line"><span style="color: #6A9955"> *</span></span>
<span class="line"><span style="color: #6A9955"> * </span><span style="color: #569CD6">@param</span><span style="color: #6A9955"> </span><span style="color: #569CD6">float</span><span style="color: #6A9955"> $percent Percentage (0–50) of data to trim at each tail.</span></span>
<span class="line"><span style="color: #6A9955"> * </span><span style="color: #569CD6">@throws</span><span style="color: #6A9955"> </span><span style="color: #4EC9B0">DomainException</span><span style="color: #6A9955"> If $percent is out of range or removes all data.</span></span>
<span class="line"><span style="color: #6A9955"> * </span><span style="color: #569CD6">@return</span><span style="color: #6A9955"> </span><span style="color: #569CD6">float</span><span style="color: #6A9955"> The trimmed mean.</span></span>
<span class="line"><span style="color: #6A9955"> */</span></span>
<span class="line"><span style="color: #569CD6">public</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">function</span><span style="color: #D4D4D4"> </span><span style="color: #DCDCAA">trimmedMean</span><span style="color: #D4D4D4">(</span><span style="color: #569CD6">float</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">$percent</span><span style="color: #D4D4D4">): </span><span style="color: #569CD6">float</span></span>
<span class="line"><span style="color: #D4D4D4">{</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #C586C0">if</span><span style="color: #D4D4D4"> (</span><span style="color: #9CDCFE">$percent</span><span style="color: #D4D4D4"> &lt; </span><span style="color: #B5CEA8">0.0</span><span style="color: #D4D4D4"> || </span><span style="color: #9CDCFE">$percent</span><span style="color: #D4D4D4"> &gt;= </span><span style="color: #B5CEA8">50.0</span><span style="color: #D4D4D4">) {</span></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #C586C0">throw</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">new</span><span style="color: #D4D4D4"> </span><span style="color: #4EC9B0">DomainException</span><span style="color: #D4D4D4">(</span><span style="color: #CE9178">&#39;Percent must be in the range 0 &lt;= p &lt; 50.&#39;</span><span style="color: #D4D4D4">);</span></span>
<span class="line"><span style="color: #D4D4D4">    }</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #9CDCFE">$count</span><span style="color: #D4D4D4"> = </span><span style="color: #DCDCAA">count</span><span style="color: #D4D4D4">(</span><span style="color: #569CD6">$this</span><span style="color: #D4D4D4">-&gt;</span><span style="color: #9CDCFE">data</span><span style="color: #D4D4D4">);</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #C586C0">if</span><span style="color: #D4D4D4"> (</span><span style="color: #9CDCFE">$count</span><span style="color: #D4D4D4"> &lt; </span><span style="color: #B5CEA8">3</span><span style="color: #D4D4D4">) {</span></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #6A9955">// Too few values to trim meaningfully; fall back to arithmetic mean</span></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #C586C0">return</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">$this</span><span style="color: #D4D4D4">-&gt;</span><span style="color: #DCDCAA">mean</span><span style="color: #D4D4D4">();</span></span>
<span class="line"><span style="color: #D4D4D4">    }</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #6A9955">// Clone and sort to preserve original order</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #9CDCFE">$sorted</span><span style="color: #D4D4D4"> = </span><span style="color: #569CD6">$this</span><span style="color: #D4D4D4">-&gt;</span><span style="color: #9CDCFE">data</span><span style="color: #D4D4D4">;</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #DCDCAA">sort</span><span style="color: #D4D4D4">(</span><span style="color: #9CDCFE">$sorted</span><span style="color: #D4D4D4">, SORT_NUMERIC);</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #6A9955">// Number of elements to trim from each end</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #9CDCFE">$k</span><span style="color: #D4D4D4"> = (</span><span style="color: #569CD6">int</span><span style="color: #D4D4D4">) </span><span style="color: #DCDCAA">floor</span><span style="color: #D4D4D4">(</span><span style="color: #9CDCFE">$count</span><span style="color: #D4D4D4"> * </span><span style="color: #9CDCFE">$percent</span><span style="color: #D4D4D4"> / </span><span style="color: #B5CEA8">100.0</span><span style="color: #D4D4D4">);</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #6A9955">// Ensure at least one value remains</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #C586C0">if</span><span style="color: #D4D4D4"> (</span><span style="color: #9CDCFE">$k</span><span style="color: #D4D4D4"> * </span><span style="color: #B5CEA8">2</span><span style="color: #D4D4D4"> &gt;= </span><span style="color: #9CDCFE">$count</span><span style="color: #D4D4D4">) {</span></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #C586C0">throw</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">new</span><span style="color: #D4D4D4"> </span><span style="color: #4EC9B0">DomainException</span><span style="color: #D4D4D4">(</span><span style="color: #CE9178">&#39;Trim percentage removes all data.&#39;</span><span style="color: #D4D4D4">);</span></span>
<span class="line"><span style="color: #D4D4D4">    }</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #9CDCFE">$trimmed</span><span style="color: #D4D4D4"> = </span><span style="color: #DCDCAA">array_slice</span><span style="color: #D4D4D4">(</span><span style="color: #9CDCFE">$sorted</span><span style="color: #D4D4D4">, </span><span style="color: #9CDCFE">$k</span><span style="color: #D4D4D4">, </span><span style="color: #9CDCFE">$count</span><span style="color: #D4D4D4"> - </span><span style="color: #B5CEA8">2</span><span style="color: #D4D4D4"> * </span><span style="color: #9CDCFE">$k</span><span style="color: #D4D4D4">);</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #C586C0">return</span><span style="color: #D4D4D4"> </span><span style="color: #DCDCAA">array_sum</span><span style="color: #D4D4D4">(</span><span style="color: #9CDCFE">$trimmed</span><span style="color: #D4D4D4">) / </span><span style="color: #DCDCAA">count</span><span style="color: #D4D4D4">(</span><span style="color: #9CDCFE">$trimmed</span><span style="color: #D4D4D4">);</span></span>
<span class="line"><span style="color: #D4D4D4">}</span></span></code></pre></div>



<p class="wp-block-paragraph">Il metodo inizia verificando che la percentuale scelta per il taglio sia sensata: deve essere maggiore o uguale a zero e strettamente minore di cinquanta, altrimenti si solleva un’eccezione; se chiedessimo, ad esempio, di eliminare il 60 % di dati a ciascuna coda non rimarrebbe nulla da mediare.</p>



<p class="wp-block-paragraph">Se il campione contiene meno di tre osservazioni, la funzione considera il taglio privo di significato e restituisce semplicemente la media aritmetica: con due valori, infatti eliminare anche solo un elemento farebbe sparire metà dei dati, mentre con uno solo non esiste nulla da troncare.</p>



<p class="wp-block-paragraph">Si procede poi a <strong>clonare</strong> l’array originale e a <strong>ordinarlo</strong> in senso crescente; la clonazione preserva l’ordine in cui i dati erano stati forniti all’oggetto, mentre l’ordinamento è indispensabile perché il troncamento viene applicato partendo dagli estremi della distribuzione.</p>



<p class="wp-block-paragraph">Il numero di elementi da scartare in ciascuna coda, indicato con <img loading="lazy" decoding="async" src="https://renor.it/wp-content/ql-cache/quicklatex.com-3422b6bb5c160593658b7c39425d9880_l3.png" class="ql-img-inline-formula quicklatex-auto-format" alt="&#107;" title="Rendered by QuickLaTeX.com" height="12" width="9" style="vertical-align: 0px;"/>, si ottiene moltiplicando la dimensione del campione per la percentuale richiesta e arrotondando verso il basso; se ad esempio abbiamo dieci valori e vogliamo una trimmed mean al 10 %, toglieremo un elemento all’inizio e uno alla fine.</p>



<p class="wp-block-paragraph">Prima di procedere, il metodo controlla che ‟due volte <img loading="lazy" decoding="async" src="https://renor.it/wp-content/ql-cache/quicklatex.com-3422b6bb5c160593658b7c39425d9880_l3.png" class="ql-img-inline-formula quicklatex-auto-format" alt="&#107;" title="Rendered by QuickLaTeX.com" height="12" width="9" style="vertical-align: 0px;"/>” non sia pari o superiore alla lunghezza dell’array: se così fosse, il taglio eliminerebbe tutti i dati e la media non avrebbe più senso; in tal caso viene lanciata un’ulteriore eccezione.</p>



<p class="wp-block-paragraph">Superata questa verifica, <code>array_slice()</code> preleva la porzione centrale che rimane dopo aver scartato i <img loading="lazy" decoding="async" src="https://renor.it/wp-content/ql-cache/quicklatex.com-3422b6bb5c160593658b7c39425d9880_l3.png" class="ql-img-inline-formula quicklatex-auto-format" alt="&#107;" title="Rendered by QuickLaTeX.com" height="12" width="9" style="vertical-align: 0px;"/> valori minori e i <img loading="lazy" decoding="async" src="https://renor.it/wp-content/ql-cache/quicklatex.com-3422b6bb5c160593658b7c39425d9880_l3.png" class="ql-img-inline-formula quicklatex-auto-format" alt="&#107;" title="Rendered by QuickLaTeX.com" height="12" width="9" style="vertical-align: 0px;"/> maggiori; su tale sottoinsieme si calcola infine la media aritmetica, che è proprio la <strong>media troncata</strong> desiderata.</p>



<p class="wp-block-paragraph">La funzione restituisce così un indicatore di tendenza centrale più <strong>robusto</strong> della media classica: gli outlier, rimossi prima del calcolo, non possono più trascinare il risultato verso valori estremi.</p>



<h2 class="wp-block-heading">Range</h2>



<p class="wp-block-paragraph">Il <strong>range</strong> è la misura di dispersione più semplice: indica l’ampiezza totale dei valori osservati, ossia la distanza fra l’estremo minimo e quello massimo del campione. Se chiamiamo</p>



<p class="wp-block-paragraph"><img loading="lazy" decoding="async" src="https://renor.it/wp-content/ql-cache/quicklatex.com-3b118489e45d1027030f5b15276e5196_l3.png" class="ql-img-inline-formula quicklatex-auto-format" alt="&#120;&#95;&#123;&#92;&#109;&#105;&#110;&#125;&#32;&#61;&#32;&#92;&#109;&#105;&#110;&#40;&#120;&#95;&#49;&#44;&#92;&#100;&#111;&#116;&#115;&#44;&#120;&#95;&#110;&#41;&#32;&#92;&#113;&#117;&#97;&#100;&#92;&#116;&#101;&#120;&#116;&#123;&#101;&#125;&#92;&#113;&#117;&#97;&#100;&#32;&#120;&#95;&#123;&#92;&#109;&#97;&#120;&#125;&#32;&#61;&#32;&#92;&#109;&#97;&#120;&#40;&#120;&#95;&#49;&#44;&#92;&#100;&#111;&#116;&#115;&#44;&#120;&#95;&#110;&#41;" title="Rendered by QuickLaTeX.com" height="19" width="403" style="vertical-align: -5px;"/>,</p>



<p class="wp-block-paragraph">allora il range <img loading="lazy" decoding="async" src="https://renor.it/wp-content/ql-cache/quicklatex.com-dae6bae3dcdac4629730754352c5e329_l3.png" class="ql-img-inline-formula quicklatex-auto-format" alt="&#82;" title="Rendered by QuickLaTeX.com" height="12" width="14" style="vertical-align: 0px;"/> si definisce come</p>



<p class="wp-block-paragraph"><img loading="lazy" decoding="async" src="https://renor.it/wp-content/ql-cache/quicklatex.com-d399b72f8b0465415f1e24a72be4f993_l3.png" class="ql-img-inline-formula quicklatex-auto-format" alt="&#82;&#32;&#61;&#32;&#120;&#95;&#123;&#92;&#109;&#97;&#120;&#125;&#32;&#92;&#59;&#45;&#92;&#59;&#32;&#120;&#95;&#123;&#92;&#109;&#105;&#110;&#125;" title="Rendered by QuickLaTeX.com" height="15" width="138" style="vertical-align: -3px;"/>.</p>



<p class="wp-block-paragraph">Pur essendo sensibile agli outlier (lo stesso valore che condiziona il massimo o il minimo condiziona anche il range), questa misura offre un’indicazione immediata della <strong>larghezza</strong> della distribuzione e viene spesso riportata accanto a medie o mediana per dare un colpo d’occhio sulla dispersione complessiva.</p>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#1E1E1E"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" data-code="/**
 * Calculates the range (max – min) of the dataset.
 *
 * @return float The range of the data.
 */
public function range(): float
{
    // min() e max() sono O(n) ma il dataset è già in memoria: soluzione lineare
    return max($this-&gt;data) - min($this-&gt;data);
}" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"><span style="color: #6A9955">/**</span></span>
<span class="line"><span style="color: #6A9955"> * Calculates the range (max – min) of the dataset.</span></span>
<span class="line"><span style="color: #6A9955"> *</span></span>
<span class="line"><span style="color: #6A9955"> * </span><span style="color: #569CD6">@return</span><span style="color: #6A9955"> </span><span style="color: #569CD6">float</span><span style="color: #6A9955"> The range of the data.</span></span>
<span class="line"><span style="color: #6A9955"> */</span></span>
<span class="line"><span style="color: #569CD6">public</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">function</span><span style="color: #D4D4D4"> </span><span style="color: #DCDCAA">range</span><span style="color: #D4D4D4">(): </span><span style="color: #569CD6">float</span></span>
<span class="line"><span style="color: #D4D4D4">{</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #6A9955">// min() e max() sono O(n) ma il dataset è già in memoria: soluzione lineare</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #C586C0">return</span><span style="color: #D4D4D4"> </span><span style="color: #DCDCAA">max</span><span style="color: #D4D4D4">(</span><span style="color: #569CD6">$this</span><span style="color: #D4D4D4">-&gt;</span><span style="color: #9CDCFE">data</span><span style="color: #D4D4D4">) - </span><span style="color: #DCDCAA">min</span><span style="color: #D4D4D4">(</span><span style="color: #569CD6">$this</span><span style="color: #D4D4D4">-&gt;</span><span style="color: #9CDCFE">data</span><span style="color: #D4D4D4">);</span></span>
<span class="line"><span style="color: #D4D4D4">}</span></span></code></pre></div>



<p class="wp-block-paragraph">Il metodo come è possibile vedere è molto essenziale. Si invocano le funzioni PHP native <code>max()</code> e <code>min()</code>che eseguono una sola scansione lineare dell&#8217;array per individuare rispettivamente il valore più grande e quello più piccolo. Sottraendo il minimo dal massimo si ottiene l&#8217;ampiezza totale del campione; il risultato è restituito come float, coerente con gli altri metodi della classe. </p>



<h2 class="wp-block-heading">Quartili e intervallo quartile (IQR)</h2>



<p class="wp-block-paragraph">Per descrivere la dispersione di un campione in modo più robusto rispetto al semplice range, si ricorre ai <strong>quartili</strong>:</p>



<ul class="wp-block-list">
<li><img loading="lazy" decoding="async" src="https://renor.it/wp-content/ql-cache/quicklatex.com-6b6b12b50fe43a209ecce557539ee185_l3.png" class="ql-img-inline-formula quicklatex-auto-format" alt="&#81;&#95;&#49;" title="Rendered by QuickLaTeX.com" height="16" width="20" style="vertical-align: -4px;"/> – 25° percentile (primo quartile)</li>



<li><img loading="lazy" decoding="async" src="https://renor.it/wp-content/ql-cache/quicklatex.com-7a8f7f7bc05736504761c873bfd99aa1_l3.png" class="ql-img-inline-formula quicklatex-auto-format" alt="&#81;&#95;&#50;" title="Rendered by QuickLaTeX.com" height="16" width="21" style="vertical-align: -4px;"/> – 50° percentile (mediana)</li>



<li><img loading="lazy" decoding="async" src="https://renor.it/wp-content/ql-cache/quicklatex.com-6cef68a5946963445c5d51e5093bd228_l3.png" class="ql-img-inline-formula quicklatex-auto-format" alt="&#81;&#95;&#51;" title="Rendered by QuickLaTeX.com" height="16" width="21" style="vertical-align: -4px;"/> – 75° percentile (terzo quartile)</li>
</ul>



<p class="wp-block-paragraph">L&#8217;intervallo interquartile si definisce come <img loading="lazy" decoding="async" src="https://renor.it/wp-content/ql-cache/quicklatex.com-b7e8e27ef6cdf0eb6f547ea71a0510cb_l3.png" class="ql-img-inline-formula quicklatex-auto-format" alt="&#92;&#116;&#101;&#120;&#116;&#123;&#73;&#81;&#82;&#125;&#32;&#61;&#32;&#81;&#95;&#51;&#32;&#45;&#32;&#81;&#95;&#49;" title="Rendered by QuickLaTeX.com" height="16" width="120" style="vertical-align: -4px;"/> e rappresenta l&#8217;ampiezza della metà centrale dei dati. È poco sensibile agli outlier perché si basa solo sui valori compresi fra il 25% e il 75% della distribuzione. </p>



<p class="wp-block-paragraph">Un uso classico dell&#8217;IQR è il rilevamento degli outlier col metodo di Tukey  (valori minori di <img loading="lazy" decoding="async" src="https://renor.it/wp-content/ql-cache/quicklatex.com-f2de8fe42732eb0aaaed68ccf31b0510_l3.png" class="ql-img-inline-formula quicklatex-auto-format" alt="&#81;&#95;&#49;&#32;&#45;&#32;&#49;&#46;&#53;&#32;&#92;&#44;&#32;&#92;&#116;&#101;&#120;&#116;&#123;&#73;&#81;&#82;&#125;" title="Rendered by QuickLaTeX.com" height="17" width="102" style="vertical-align: -4px;"/> o maggiori di <img loading="lazy" decoding="async" src="https://renor.it/wp-content/ql-cache/quicklatex.com-12b8491f4b68c771f42e0b54a111bc92_l3.png" class="ql-img-inline-formula quicklatex-auto-format" alt="&#81;&#95;&#51;&#32;&#43;&#32;&#49;&#46;&#53;&#32;&#92;&#44;&#32;&#92;&#116;&#101;&#120;&#116;&#123;&#73;&#81;&#82;&#125;" title="Rendered by QuickLaTeX.com" height="17" width="102" style="vertical-align: -4px;"/>)</p>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#1E1E1E"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" data-code="/**
 * Returns an array with the first, second (median) and third quartile.
 *
 * Method: &quot;Tukey hinges&quot;.
 *  - Sort the dataset.
 *  - For Q1 and Q3, exclude the median when the sample size is odd.
 *
 * @return float[] [Q1, Q2, Q3] in ascending order.
 */
 public function quartiles(): array
    {
        $sorted = $this-&gt;data;
        sort($sorted, SORT_NUMERIC);

        $n = count($sorted);
        if ($n === 1) {
            return [$sorted[0], $sorted[0], $sorted[0]];
        }
        $mid = intdiv($n, 2);

        // Median (Q2)
        $q2 = ($n % 2 === 0)
            ? ($sorted[$mid - 1] + $sorted[$mid]) / 2.0
            : (float) $sorted[$mid];

        // Lower half (exclude median if n is odd)
        $lower = array_slice($sorted, 0, $mid);
        // Upper half (exclude median if n is odd)
        $upper = array_slice($sorted, ($n % 2 === 0) ? $mid : $mid + 1);

        // Q1 and Q3 are medians of the two halves
        $q1 = $this-&gt;medianOfArray($lower);
        $q3 = $this-&gt;medianOfArray($upper);

        return [$q1, $q2, $q3];
    }

/**
 * Calculates the interquartile range (Q3 – Q1).
 *
 * @return float The interquartile range.
 */
public function iqr(): float
{
    [$q1, , $q3] = $this-&gt;quartiles();
    return $q3 - $q1;
}

/* ---------- Helper ---------- */
/**
 * Median of a pre-sorted array (helper for quartiles).
 *
 * @param float[] $arr Sorted numeric array.
 * @return float Median value.
 */
private function medianOfArray(array $arr): float
{
    $count = count($arr);
    if ($count === 0) {
        throw new LogicException('Cannot compute median of an empty array.');
    }

    $mid = intdiv($count, 2);

    return ($count % 2 === 0)
        ? ($arr[$mid - 1] + $arr[$mid]) / 2.0
        : (float) $arr[$mid];
}" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"><span style="color: #6A9955">/**</span></span>
<span class="line"><span style="color: #6A9955"> * Returns an array with the first, second (median) and third quartile.</span></span>
<span class="line"><span style="color: #6A9955"> *</span></span>
<span class="line"><span style="color: #6A9955"> * Method: &quot;Tukey hinges&quot;.</span></span>
<span class="line"><span style="color: #6A9955"> *  - Sort the dataset.</span></span>
<span class="line"><span style="color: #6A9955"> *  - For Q1 and Q3, exclude the median when the sample size is odd.</span></span>
<span class="line"><span style="color: #6A9955"> *</span></span>
<span class="line"><span style="color: #6A9955"> * </span><span style="color: #569CD6">@return</span><span style="color: #6A9955"> </span><span style="color: #569CD6">float[]</span><span style="color: #6A9955"> [Q1, Q2, Q3] in ascending order.</span></span>
<span class="line"><span style="color: #6A9955"> */</span></span>
<span class="line"><span style="color: #D4D4D4"> </span><span style="color: #569CD6">public</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">function</span><span style="color: #D4D4D4"> </span><span style="color: #DCDCAA">quartiles</span><span style="color: #D4D4D4">(): </span><span style="color: #569CD6">array</span></span>
<span class="line"><span style="color: #D4D4D4">    {</span></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #9CDCFE">$sorted</span><span style="color: #D4D4D4"> = </span><span style="color: #569CD6">$this</span><span style="color: #D4D4D4">-&gt;</span><span style="color: #9CDCFE">data</span><span style="color: #D4D4D4">;</span></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #DCDCAA">sort</span><span style="color: #D4D4D4">(</span><span style="color: #9CDCFE">$sorted</span><span style="color: #D4D4D4">, SORT_NUMERIC);</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #9CDCFE">$n</span><span style="color: #D4D4D4"> = </span><span style="color: #DCDCAA">count</span><span style="color: #D4D4D4">(</span><span style="color: #9CDCFE">$sorted</span><span style="color: #D4D4D4">);</span></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #C586C0">if</span><span style="color: #D4D4D4"> (</span><span style="color: #9CDCFE">$n</span><span style="color: #D4D4D4"> === </span><span style="color: #B5CEA8">1</span><span style="color: #D4D4D4">) {</span></span>
<span class="line"><span style="color: #D4D4D4">            </span><span style="color: #C586C0">return</span><span style="color: #D4D4D4"> [</span><span style="color: #9CDCFE">$sorted</span><span style="color: #D4D4D4">[</span><span style="color: #B5CEA8">0</span><span style="color: #D4D4D4">], </span><span style="color: #9CDCFE">$sorted</span><span style="color: #D4D4D4">[</span><span style="color: #B5CEA8">0</span><span style="color: #D4D4D4">], </span><span style="color: #9CDCFE">$sorted</span><span style="color: #D4D4D4">[</span><span style="color: #B5CEA8">0</span><span style="color: #D4D4D4">]];</span></span>
<span class="line"><span style="color: #D4D4D4">        }</span></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #9CDCFE">$mid</span><span style="color: #D4D4D4"> = </span><span style="color: #DCDCAA">intdiv</span><span style="color: #D4D4D4">(</span><span style="color: #9CDCFE">$n</span><span style="color: #D4D4D4">, </span><span style="color: #B5CEA8">2</span><span style="color: #D4D4D4">);</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #6A9955">// Median (Q2)</span></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #9CDCFE">$q2</span><span style="color: #D4D4D4"> = (</span><span style="color: #9CDCFE">$n</span><span style="color: #D4D4D4"> % </span><span style="color: #B5CEA8">2</span><span style="color: #D4D4D4"> === </span><span style="color: #B5CEA8">0</span><span style="color: #D4D4D4">)</span></span>
<span class="line"><span style="color: #D4D4D4">            ? (</span><span style="color: #9CDCFE">$sorted</span><span style="color: #D4D4D4">[</span><span style="color: #9CDCFE">$mid</span><span style="color: #D4D4D4"> - </span><span style="color: #B5CEA8">1</span><span style="color: #D4D4D4">] + </span><span style="color: #9CDCFE">$sorted</span><span style="color: #D4D4D4">[</span><span style="color: #9CDCFE">$mid</span><span style="color: #D4D4D4">]) / </span><span style="color: #B5CEA8">2.0</span></span>
<span class="line"><span style="color: #D4D4D4">            : (</span><span style="color: #569CD6">float</span><span style="color: #D4D4D4">) </span><span style="color: #9CDCFE">$sorted</span><span style="color: #D4D4D4">[</span><span style="color: #9CDCFE">$mid</span><span style="color: #D4D4D4">];</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #6A9955">// Lower half (exclude median if n is odd)</span></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #9CDCFE">$lower</span><span style="color: #D4D4D4"> = </span><span style="color: #DCDCAA">array_slice</span><span style="color: #D4D4D4">(</span><span style="color: #9CDCFE">$sorted</span><span style="color: #D4D4D4">, </span><span style="color: #B5CEA8">0</span><span style="color: #D4D4D4">, </span><span style="color: #9CDCFE">$mid</span><span style="color: #D4D4D4">);</span></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #6A9955">// Upper half (exclude median if n is odd)</span></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #9CDCFE">$upper</span><span style="color: #D4D4D4"> = </span><span style="color: #DCDCAA">array_slice</span><span style="color: #D4D4D4">(</span><span style="color: #9CDCFE">$sorted</span><span style="color: #D4D4D4">, (</span><span style="color: #9CDCFE">$n</span><span style="color: #D4D4D4"> % </span><span style="color: #B5CEA8">2</span><span style="color: #D4D4D4"> === </span><span style="color: #B5CEA8">0</span><span style="color: #D4D4D4">) ? </span><span style="color: #9CDCFE">$mid</span><span style="color: #D4D4D4"> : </span><span style="color: #9CDCFE">$mid</span><span style="color: #D4D4D4"> + </span><span style="color: #B5CEA8">1</span><span style="color: #D4D4D4">);</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #6A9955">// Q1 and Q3 are medians of the two halves</span></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #9CDCFE">$q1</span><span style="color: #D4D4D4"> = </span><span style="color: #569CD6">$this</span><span style="color: #D4D4D4">-&gt;</span><span style="color: #DCDCAA">medianOfArray</span><span style="color: #D4D4D4">(</span><span style="color: #9CDCFE">$lower</span><span style="color: #D4D4D4">);</span></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #9CDCFE">$q3</span><span style="color: #D4D4D4"> = </span><span style="color: #569CD6">$this</span><span style="color: #D4D4D4">-&gt;</span><span style="color: #DCDCAA">medianOfArray</span><span style="color: #D4D4D4">(</span><span style="color: #9CDCFE">$upper</span><span style="color: #D4D4D4">);</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #C586C0">return</span><span style="color: #D4D4D4"> [</span><span style="color: #9CDCFE">$q1</span><span style="color: #D4D4D4">, </span><span style="color: #9CDCFE">$q2</span><span style="color: #D4D4D4">, </span><span style="color: #9CDCFE">$q3</span><span style="color: #D4D4D4">];</span></span>
<span class="line"><span style="color: #D4D4D4">    }</span></span>
<span class="line"></span>
<span class="line"><span style="color: #6A9955">/**</span></span>
<span class="line"><span style="color: #6A9955"> * Calculates the interquartile range (Q3 – Q1).</span></span>
<span class="line"><span style="color: #6A9955"> *</span></span>
<span class="line"><span style="color: #6A9955"> * </span><span style="color: #569CD6">@return</span><span style="color: #6A9955"> </span><span style="color: #569CD6">float</span><span style="color: #6A9955"> The interquartile range.</span></span>
<span class="line"><span style="color: #6A9955"> */</span></span>
<span class="line"><span style="color: #569CD6">public</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">function</span><span style="color: #D4D4D4"> </span><span style="color: #DCDCAA">iqr</span><span style="color: #D4D4D4">(): </span><span style="color: #569CD6">float</span></span>
<span class="line"><span style="color: #D4D4D4">{</span></span>
<span class="line"><span style="color: #D4D4D4">    [</span><span style="color: #9CDCFE">$q1</span><span style="color: #D4D4D4">, , </span><span style="color: #9CDCFE">$q3</span><span style="color: #D4D4D4">] = </span><span style="color: #569CD6">$this</span><span style="color: #D4D4D4">-&gt;</span><span style="color: #DCDCAA">quartiles</span><span style="color: #D4D4D4">();</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #C586C0">return</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">$q3</span><span style="color: #D4D4D4"> - </span><span style="color: #9CDCFE">$q1</span><span style="color: #D4D4D4">;</span></span>
<span class="line"><span style="color: #D4D4D4">}</span></span>
<span class="line"></span>
<span class="line"><span style="color: #6A9955">/* ---------- Helper ---------- */</span></span>
<span class="line"><span style="color: #6A9955">/**</span></span>
<span class="line"><span style="color: #6A9955"> * Median of a pre-sorted array (helper for quartiles).</span></span>
<span class="line"><span style="color: #6A9955"> *</span></span>
<span class="line"><span style="color: #6A9955"> * </span><span style="color: #569CD6">@param</span><span style="color: #6A9955"> </span><span style="color: #569CD6">float[]</span><span style="color: #6A9955"> $arr Sorted numeric array.</span></span>
<span class="line"><span style="color: #6A9955"> * </span><span style="color: #569CD6">@return</span><span style="color: #6A9955"> </span><span style="color: #569CD6">float</span><span style="color: #6A9955"> Median value.</span></span>
<span class="line"><span style="color: #6A9955"> */</span></span>
<span class="line"><span style="color: #569CD6">private</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">function</span><span style="color: #D4D4D4"> </span><span style="color: #DCDCAA">medianOfArray</span><span style="color: #D4D4D4">(</span><span style="color: #569CD6">array</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">$arr</span><span style="color: #D4D4D4">): </span><span style="color: #569CD6">float</span></span>
<span class="line"><span style="color: #D4D4D4">{</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #9CDCFE">$count</span><span style="color: #D4D4D4"> = </span><span style="color: #DCDCAA">count</span><span style="color: #D4D4D4">(</span><span style="color: #9CDCFE">$arr</span><span style="color: #D4D4D4">);</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #C586C0">if</span><span style="color: #D4D4D4"> (</span><span style="color: #9CDCFE">$count</span><span style="color: #D4D4D4"> === </span><span style="color: #B5CEA8">0</span><span style="color: #D4D4D4">) {</span></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #C586C0">throw</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">new</span><span style="color: #D4D4D4"> </span><span style="color: #4EC9B0">LogicException</span><span style="color: #D4D4D4">(</span><span style="color: #CE9178">&#39;Cannot compute median of an empty array.&#39;</span><span style="color: #D4D4D4">);</span></span>
<span class="line"><span style="color: #D4D4D4">    }</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #9CDCFE">$mid</span><span style="color: #D4D4D4"> = </span><span style="color: #DCDCAA">intdiv</span><span style="color: #D4D4D4">(</span><span style="color: #9CDCFE">$count</span><span style="color: #D4D4D4">, </span><span style="color: #B5CEA8">2</span><span style="color: #D4D4D4">);</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #C586C0">return</span><span style="color: #D4D4D4"> (</span><span style="color: #9CDCFE">$count</span><span style="color: #D4D4D4"> % </span><span style="color: #B5CEA8">2</span><span style="color: #D4D4D4"> === </span><span style="color: #B5CEA8">0</span><span style="color: #D4D4D4">)</span></span>
<span class="line"><span style="color: #D4D4D4">        ? (</span><span style="color: #9CDCFE">$arr</span><span style="color: #D4D4D4">[</span><span style="color: #9CDCFE">$mid</span><span style="color: #D4D4D4"> - </span><span style="color: #B5CEA8">1</span><span style="color: #D4D4D4">] + </span><span style="color: #9CDCFE">$arr</span><span style="color: #D4D4D4">[</span><span style="color: #9CDCFE">$mid</span><span style="color: #D4D4D4">]) / </span><span style="color: #B5CEA8">2.0</span></span>
<span class="line"><span style="color: #D4D4D4">        : (</span><span style="color: #569CD6">float</span><span style="color: #D4D4D4">) </span><span style="color: #9CDCFE">$arr</span><span style="color: #D4D4D4">[</span><span style="color: #9CDCFE">$mid</span><span style="color: #D4D4D4">];</span></span>
<span class="line"><span style="color: #D4D4D4">}</span></span></code></pre></div>



<p class="wp-block-paragraph">Quando il metodo <code>quartiles()</code> viene invocato, la prima cosa che fa è creare una copia dei dati interni e ordinarla in senso crescente; questa copia protegge l’ordine originale fornito dall’utente e consente di lavorare con un vettore monotonicamente ordinato, prerequisito indispensabile per individuare i quartili. Subito dopo, la variabile <code>$n</code> memorizza la lunghezza del campione e <code>$mid</code> rappresenta l’indice centrale calcolato tramite divisione intera. Con queste due informazioni si procede a determinare la mediana dell’intero campione, che diventa il secondo quartile <img loading="lazy" decoding="async" src="https://renor.it/wp-content/ql-cache/quicklatex.com-7a8f7f7bc05736504761c873bfd99aa1_l3.png" class="ql-img-inline-formula quicklatex-auto-format" alt="&#81;&#95;&#50;" title="Rendered by QuickLaTeX.com" height="16" width="21" style="vertical-align: -4px;"/>; se il numero di osservazioni è pari, la mediana è la media aritmetica dei due valori centrali, mentre nel caso dispari coincide con il valore in posizione centrale.</p>



<p class="wp-block-paragraph">Una volta noto <img loading="lazy" decoding="async" src="https://renor.it/wp-content/ql-cache/quicklatex.com-7a8f7f7bc05736504761c873bfd99aa1_l3.png" class="ql-img-inline-formula quicklatex-auto-format" alt="&#81;&#95;&#50;" title="Rendered by QuickLaTeX.com" height="16" width="21" style="vertical-align: -4px;"/>, l’array ordinato viene spezzato in due metà. Se la numerosità è dispari la mediana non va inclusa né nella parte inferiore né in quella superiore, perciò la funzione <code>array_slice</code> la esclude esplicitamente; se è pari la suddivisione avviene esattamente a metà. A questo punto entrano in gioco i quartili estremi: per calcolare <img loading="lazy" decoding="async" src="https://renor.it/wp-content/ql-cache/quicklatex.com-6b6b12b50fe43a209ecce557539ee185_l3.png" class="ql-img-inline-formula quicklatex-auto-format" alt="&#81;&#95;&#49;" title="Rendered by QuickLaTeX.com" height="16" width="20" style="vertical-align: -4px;"/> e <img loading="lazy" decoding="async" src="https://renor.it/wp-content/ql-cache/quicklatex.com-6cef68a5946963445c5d51e5093bd228_l3.png" class="ql-img-inline-formula quicklatex-auto-format" alt="&#81;&#95;&#51;" title="Rendered by QuickLaTeX.com" height="16" width="21" style="vertical-align: -4px;"/> non si crea alcun nuovo oggetto, bensì si invoca l’helper privato <code>medianOfArray</code> sulle due metà già ordinate. Questa piccola routine riceve un vettore, ne conta gli elementi, determina l’indice centrale e restituisce la mediana con la stessa logica adottata in precedenza; il tutto resta confinato all’interno della classe, così l’interfaccia pubblica rimane pulita e ogni duplicazione di codice è evitata.</p>



<p class="wp-block-paragraph">Il metodo <code>quartiles()</code> restituisce infine un array con i tre valori <img loading="lazy" decoding="async" src="https://renor.it/wp-content/ql-cache/quicklatex.com-2a57835ccc4419c852fb77d64952d763_l3.png" class="ql-img-inline-formula quicklatex-auto-format" alt="&#91;&#81;&#95;&#49;&#44;&#32;&#81;&#95;&#50;&#44;&#32;&#81;&#95;&#51;&#93;" title="Rendered by QuickLaTeX.com" height="18" width="87" style="vertical-align: -5px;"/> in ordine crescente. Il fratello <code>iqr()</code> si limita a scompattare quell’array, sottrae <img loading="lazy" decoding="async" src="https://renor.it/wp-content/ql-cache/quicklatex.com-6b6b12b50fe43a209ecce557539ee185_l3.png" class="ql-img-inline-formula quicklatex-auto-format" alt="&#81;&#95;&#49;" title="Rendered by QuickLaTeX.com" height="16" width="20" style="vertical-align: -4px;"/> da <img loading="lazy" decoding="async" src="https://renor.it/wp-content/ql-cache/quicklatex.com-6cef68a5946963445c5d51e5093bd228_l3.png" class="ql-img-inline-formula quicklatex-auto-format" alt="&#81;&#95;&#51;" title="Rendered by QuickLaTeX.com" height="16" width="21" style="vertical-align: -4px;"/> e ritorna l’intervallo interquartile, fornendo in un’unica chiamata la misura di dispersione più robusta della classe.</p>



<p class="wp-block-paragraph">In questo assetto la logica della mediana resta centralizzata dentro l’helper privato, viene riutilizzata sia per i quartili sia, in modo implicito, per qualsiasi eventuale altra funzionalità interna che avesse bisogno di calcolare una mediana su un sottoinsieme ordinato, mentre l’API pubblica continua ad offrire metodi autodidattici e facili da comprendere per chi integrerà la tua libreria.</p>



<h2 class="wp-block-heading">Varianza</h2>



<p class="wp-block-paragraph">Per misurare quanto i valori si discostino dalla loro tendenza centrale si introduce la <strong>varianza</strong>, che calcola la media dei quadrati degli scarti dalla media aritmetica. Date <img loading="lazy" decoding="async" src="https://renor.it/wp-content/ql-cache/quicklatex.com-b170995d512c659d8668b4e42e1fef6b_l3.png" class="ql-img-inline-formula quicklatex-auto-format" alt="&#110;" title="Rendered by QuickLaTeX.com" height="8" width="11" style="vertical-align: 0px;"/> osservazioni <img loading="lazy" decoding="async" src="https://renor.it/wp-content/ql-cache/quicklatex.com-08f4f7c471a86ab23d63ecf2d1c0071b_l3.png" class="ql-img-inline-formula quicklatex-auto-format" alt="&#120;&#95;&#49;&#44;&#32;&#120;&#95;&#50;&#44;&#32;&#92;&#100;&#111;&#116;&#115;&#44;&#32;&#120;&#95;&#110;&#32;" title="Rendered by QuickLaTeX.com" height="12" width="101" style="vertical-align: -4px;"/> con media <img loading="lazy" decoding="async" src="https://renor.it/wp-content/ql-cache/quicklatex.com-20ebc7ea21d727ebe3840c06a433ab09_l3.png" class="ql-img-inline-formula quicklatex-auto-format" alt="&#92;&#98;&#97;&#114;&#123;&#120;&#125;" title="Rendered by QuickLaTeX.com" height="11" width="10" style="vertical-align: 0px;"/>, la <strong>varianza della popolazione</strong> si definisce</p>



<p class="wp-block-paragraph"><img loading="lazy" decoding="async" src="https://renor.it/wp-content/ql-cache/quicklatex.com-3cde5d7135396b988fc10797bf8b06e4_l3.png" class="ql-img-inline-formula quicklatex-auto-format" alt="&#92;&#115;&#105;&#103;&#109;&#97;&#94;&#123;&#50;&#125;&#32;&#92;&#59;&#61;&#92;&#59;&#32;&#92;&#102;&#114;&#97;&#99;&#123;&#49;&#125;&#123;&#110;&#125;&#92;&#115;&#117;&#109;&#95;&#123;&#105;&#61;&#49;&#125;&#94;&#123;&#110;&#125;&#40;&#120;&#95;&#105;&#32;&#45;&#32;&#92;&#98;&#97;&#114;&#123;&#120;&#125;&#41;&#94;&#123;&#50;&#125;" title="Rendered by QuickLaTeX.com" height="22" width="177" style="vertical-align: -6px;"/></p>



<p class="wp-block-paragraph">Se invece i dati rappresentano un <strong>campione</strong> estratto da una popolazione più ampia, lo stimatore corretto (varianza campionaria) divide per <img loading="lazy" decoding="async" src="https://renor.it/wp-content/ql-cache/quicklatex.com-f30b71e7fcec69d119f30f67cf09c975_l3.png" class="ql-img-inline-formula quicklatex-auto-format" alt="&#110;&#45;&#49;" title="Rendered by QuickLaTeX.com" height="12" width="40" style="vertical-align: 0px;"/>:</p>



<p class="wp-block-paragraph"><img loading="lazy" decoding="async" src="https://renor.it/wp-content/ql-cache/quicklatex.com-932ecac38eb830d655be06b4360392dd_l3.png" class="ql-img-inline-formula quicklatex-auto-format" alt="&#115;&#94;&#123;&#50;&#125;&#32;&#92;&#59;&#61;&#92;&#59;&#32;&#92;&#102;&#114;&#97;&#99;&#123;&#49;&#125;&#123;&#110;&#45;&#49;&#125;&#92;&#115;&#117;&#109;&#95;&#123;&#105;&#61;&#49;&#125;&#94;&#123;&#110;&#125;&#40;&#120;&#95;&#105;&#32;&#45;&#32;&#92;&#98;&#97;&#114;&#123;&#120;&#125;&#41;&#94;&#123;&#50;&#125;" title="Rendered by QuickLaTeX.com" height="22" width="192" style="vertical-align: -6px;"/></p>



<p class="wp-block-paragraph">La varianza restituisce un valore <strong>quadratico</strong>: è sempre non negativa e cresce rapidamente quando gli scarti aumentano, perciò un suo uso frequente è passare alla radice quadrata (deviazione standard) per tornare alle stesse unità di misura dei dati.</p>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#1E1E1E"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" data-code="/**
 * Calculates the variance of the dataset.
 *
 * @param bool $sample If true, uses (n-1) in the denominator (sample variance).
 *                     If false, uses n (population variance).
 * @return float The variance value.
 */
public function variance(bool $sample = false): float
{
    $n = count($this-&gt;data);

    // For a single value, population variance is 0, sample variance is undefined
    if ($n &lt; 2 &amp;&amp; $sample) {
        throw new DomainException('Sample variance requires at least two observations.');
    }
    if ($n === 1) {
        return 0.0;
    }

    $mean = $this-&gt;mean();
    $sumSquares = 0.0;

    foreach ($this-&gt;data as $v) {
        $diff        = $v - $mean;
        $sumSquares += $diff * $diff;
    }

    $denominator = $sample ? ($n - 1) : $n;
    return $sumSquares / $denominator;
}" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"><span style="color: #6A9955">/**</span></span>
<span class="line"><span style="color: #6A9955"> * Calculates the variance of the dataset.</span></span>
<span class="line"><span style="color: #6A9955"> *</span></span>
<span class="line"><span style="color: #6A9955"> * </span><span style="color: #569CD6">@param</span><span style="color: #6A9955"> </span><span style="color: #569CD6">bool</span><span style="color: #6A9955"> $sample If true, uses (n-1) in the denominator (sample variance).</span></span>
<span class="line"><span style="color: #6A9955"> *                     If false, uses n (population variance).</span></span>
<span class="line"><span style="color: #6A9955"> * </span><span style="color: #569CD6">@return</span><span style="color: #6A9955"> </span><span style="color: #569CD6">float</span><span style="color: #6A9955"> The variance value.</span></span>
<span class="line"><span style="color: #6A9955"> */</span></span>
<span class="line"><span style="color: #569CD6">public</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">function</span><span style="color: #D4D4D4"> </span><span style="color: #DCDCAA">variance</span><span style="color: #D4D4D4">(</span><span style="color: #569CD6">bool</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">$sample</span><span style="color: #D4D4D4"> = </span><span style="color: #569CD6">false</span><span style="color: #D4D4D4">): </span><span style="color: #569CD6">float</span></span>
<span class="line"><span style="color: #D4D4D4">{</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #9CDCFE">$n</span><span style="color: #D4D4D4"> = </span><span style="color: #DCDCAA">count</span><span style="color: #D4D4D4">(</span><span style="color: #569CD6">$this</span><span style="color: #D4D4D4">-&gt;</span><span style="color: #9CDCFE">data</span><span style="color: #D4D4D4">);</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #6A9955">// For a single value, population variance is 0, sample variance is undefined</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #C586C0">if</span><span style="color: #D4D4D4"> (</span><span style="color: #9CDCFE">$n</span><span style="color: #D4D4D4"> &lt; </span><span style="color: #B5CEA8">2</span><span style="color: #D4D4D4"> &amp;&amp; </span><span style="color: #9CDCFE">$sample</span><span style="color: #D4D4D4">) {</span></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #C586C0">throw</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">new</span><span style="color: #D4D4D4"> </span><span style="color: #4EC9B0">DomainException</span><span style="color: #D4D4D4">(</span><span style="color: #CE9178">&#39;Sample variance requires at least two observations.&#39;</span><span style="color: #D4D4D4">);</span></span>
<span class="line"><span style="color: #D4D4D4">    }</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #C586C0">if</span><span style="color: #D4D4D4"> (</span><span style="color: #9CDCFE">$n</span><span style="color: #D4D4D4"> === </span><span style="color: #B5CEA8">1</span><span style="color: #D4D4D4">) {</span></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #C586C0">return</span><span style="color: #D4D4D4"> </span><span style="color: #B5CEA8">0.0</span><span style="color: #D4D4D4">;</span></span>
<span class="line"><span style="color: #D4D4D4">    }</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #9CDCFE">$mean</span><span style="color: #D4D4D4"> = </span><span style="color: #569CD6">$this</span><span style="color: #D4D4D4">-&gt;</span><span style="color: #DCDCAA">mean</span><span style="color: #D4D4D4">();</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #9CDCFE">$sumSquares</span><span style="color: #D4D4D4"> = </span><span style="color: #B5CEA8">0.0</span><span style="color: #D4D4D4">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #C586C0">foreach</span><span style="color: #D4D4D4"> (</span><span style="color: #569CD6">$this</span><span style="color: #D4D4D4">-&gt;</span><span style="color: #9CDCFE">data</span><span style="color: #D4D4D4"> as </span><span style="color: #9CDCFE">$v</span><span style="color: #D4D4D4">) {</span></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #9CDCFE">$diff</span><span style="color: #D4D4D4">        = </span><span style="color: #9CDCFE">$v</span><span style="color: #D4D4D4"> - </span><span style="color: #9CDCFE">$mean</span><span style="color: #D4D4D4">;</span></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #9CDCFE">$sumSquares</span><span style="color: #D4D4D4"> += </span><span style="color: #9CDCFE">$diff</span><span style="color: #D4D4D4"> * </span><span style="color: #9CDCFE">$diff</span><span style="color: #D4D4D4">;</span></span>
<span class="line"><span style="color: #D4D4D4">    }</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #9CDCFE">$denominator</span><span style="color: #D4D4D4"> = </span><span style="color: #9CDCFE">$sample</span><span style="color: #D4D4D4"> ? (</span><span style="color: #9CDCFE">$n</span><span style="color: #D4D4D4"> - </span><span style="color: #B5CEA8">1</span><span style="color: #D4D4D4">) : </span><span style="color: #9CDCFE">$n</span><span style="color: #D4D4D4">;</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #C586C0">return</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">$sumSquares</span><span style="color: #D4D4D4"> / </span><span style="color: #9CDCFE">$denominator</span><span style="color: #D4D4D4">;</span></span>
<span class="line"><span style="color: #D4D4D4">}</span></span></code></pre></div>



<p class="wp-block-paragraph"><br>Il metodo riceve un flag che indica se calcolare la varianza della popolazione o lo stimatore campionario. Inizia valutando la numerosità del dataset: con un solo valore la varianza di popolazione è per definizione zero, mentre quella campionaria non esiste e viene sollevata un’eccezione. Una volta nota la media, il ciclo attraversa ogni osservazione, sottrae la media, eleva lo scarto al quadrato e lo accumula. Terminata la sommatoria, la divisione avviene per <img loading="lazy" decoding="async" src="https://renor.it/wp-content/ql-cache/quicklatex.com-b170995d512c659d8668b4e42e1fef6b_l3.png" class="ql-img-inline-formula quicklatex-auto-format" alt="&#110;" title="Rendered by QuickLaTeX.com" height="8" width="11" style="vertical-align: 0px;"/> o <img loading="lazy" decoding="async" src="https://renor.it/wp-content/ql-cache/quicklatex.com-f30b71e7fcec69d119f30f67cf09c975_l3.png" class="ql-img-inline-formula quicklatex-auto-format" alt="&#110;&#45;&#49;" title="Rendered by QuickLaTeX.com" height="12" width="40" style="vertical-align: 0px;"/> a seconda del contesto specificato, restituendo così la misura di dispersione desiderata.</p>



<h2 class="wp-block-heading">Deviazione standard</h2>



<p class="wp-block-paragraph"><br>La <strong>deviazione standard</strong> non è altro che la radice quadrata della varianza: serve a riportare la misura di dispersione alle stesse unità dei dati originali. Se la varianza indica “quanti quadrati di unità” si distanziano in media le osservazioni dalla loro media, la deviazione standard esprime quello scarto in unità lineari, dunque risulta molto più intuitiva per un lettore non specialista. Per la popolazione la si ottiene come <img loading="lazy" decoding="async" src="https://renor.it/wp-content/ql-cache/quicklatex.com-084a79d5a7bbe330f12ebed3c76aa066_l3.png" class="ql-img-inline-formula quicklatex-auto-format" alt="&#92;&#115;&#105;&#103;&#109;&#97;&#32;&#61;&#32;&#92;&#115;&#113;&#114;&#116;&#123;&#92;&#115;&#105;&#103;&#109;&#97;&#94;&#123;&#50;&#125;&#125;" title="Rendered by QuickLaTeX.com" height="18" width="68" style="vertical-align: -1px;"/>, mentre nel caso campionario si usa <img loading="lazy" decoding="async" src="https://renor.it/wp-content/ql-cache/quicklatex.com-2aa1eaecb6b446e07c4b2edf8fa49880_l3.png" class="ql-img-inline-formula quicklatex-auto-format" alt="&#115;&#32;&#61;&#32;&#92;&#115;&#113;&#114;&#116;&#123;&#115;&#94;&#123;&#50;&#125;&#125;" title="Rendered by QuickLaTeX.com" height="18" width="64" style="vertical-align: -1px;"/>. Valori di deviazione standard piccoli raccontano una distribuzione raccolta intorno alla media; valori grandi parlano di dati molto dispersi.</p>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#1E1E1E"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" data-code="/**
 * Calculates the standard deviation of the dataset.
 *
 * @param bool $sample If true, returns the sample standard deviation (n-1 in the denominator).
 *                     If false, returns the population standard deviation.
 * @return float The standard deviation.
 */
public function standardDeviation(bool $sample = false): float
{
    return sqrt($this-&gt;variance($sample));
}" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"><span style="color: #6A9955">/**</span></span>
<span class="line"><span style="color: #6A9955"> * Calculates the standard deviation of the dataset.</span></span>
<span class="line"><span style="color: #6A9955"> *</span></span>
<span class="line"><span style="color: #6A9955"> * </span><span style="color: #569CD6">@param</span><span style="color: #6A9955"> </span><span style="color: #569CD6">bool</span><span style="color: #6A9955"> $sample If true, returns the sample standard deviation (n-1 in the denominator).</span></span>
<span class="line"><span style="color: #6A9955"> *                     If false, returns the population standard deviation.</span></span>
<span class="line"><span style="color: #6A9955"> * </span><span style="color: #569CD6">@return</span><span style="color: #6A9955"> </span><span style="color: #569CD6">float</span><span style="color: #6A9955"> The standard deviation.</span></span>
<span class="line"><span style="color: #6A9955"> */</span></span>
<span class="line"><span style="color: #569CD6">public</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">function</span><span style="color: #D4D4D4"> </span><span style="color: #DCDCAA">standardDeviation</span><span style="color: #D4D4D4">(</span><span style="color: #569CD6">bool</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">$sample</span><span style="color: #D4D4D4"> = </span><span style="color: #569CD6">false</span><span style="color: #D4D4D4">): </span><span style="color: #569CD6">float</span></span>
<span class="line"><span style="color: #D4D4D4">{</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #C586C0">return</span><span style="color: #D4D4D4"> </span><span style="color: #DCDCAA">sqrt</span><span style="color: #D4D4D4">(</span><span style="color: #569CD6">$this</span><span style="color: #D4D4D4">-&gt;</span><span style="color: #DCDCAA">variance</span><span style="color: #D4D4D4">(</span><span style="color: #9CDCFE">$sample</span><span style="color: #D4D4D4">));</span></span>
<span class="line"><span style="color: #D4D4D4">}</span></span></code></pre></div>



<p class="wp-block-paragraph"><br>Il metodo non contiene logica aggiuntiva: richiama semplicemente <code>variance()</code> con lo stesso flag e ne restituisce la radice quadrata, delegando all’algoritmo già collaudato tutta la parte di calcolo e di controlli di dominio.</p>



<h2 class="wp-block-heading">Errore standard della media</h2>



<p class="wp-block-paragraph">Quando dalla popolazione osserviamo soltanto un campione, la media campionaria è una stima soggetta a fluttuazioni: più il campione è piccolo, più la stima può variare da un campione all’altro. L’<strong>errore standard della media</strong> (in inglese <em>Standard Error of the Mean</em>, SEM) quantifica esattamente questa variabilità prevista. Se s è la deviazione standard campionaria e n è la numerosità del campione, l’errore standard si calcola con</p>



<p class="wp-block-paragraph"><img loading="lazy" decoding="async" src="https://renor.it/wp-content/ql-cache/quicklatex.com-01ae367d3efe370932420a9b723937f4_l3.png" class="ql-img-inline-formula quicklatex-auto-format" alt="&#92;&#116;&#101;&#120;&#116;&#123;&#83;&#69;&#77;&#125;&#32;&#92;&#59;&#61;&#92;&#59;&#32;&#92;&#102;&#114;&#97;&#99;&#123;&#115;&#125;&#123;&#92;&#115;&#113;&#114;&#116;&#123;&#110;&#125;&#125;" title="Rendered by QuickLaTeX.com" height="24" width="94" style="vertical-align: -11px;"/>.</p>



<p class="wp-block-paragraph">Un SEM contenuto indica che la media calcolata su quel campione è verosimilmente vicina alla media vera della popolazione; un SEM ampio suggerisce un’incertezza maggiore. Il SEM è inoltre la base per costruire gli intervalli di confidenza della media.</p>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#1E1E1E"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" data-code="/**
 * Calculates the standard error of the mean (SEM) of the dataset.
 *
 * SEM = sample standard deviation / sqrt(n)
 * Requires at least two observations.
 *
 * @throws DomainException If the dataset size is less than 2.
 * @return float The standard error of the mean.
 */
public function standardError(): float
{
    $n = count($this-&gt;data);

    if ($n &lt; 2) {
        throw new DomainException('Standard error requires at least two observations.');
    }

    return $this-&gt;standardDeviation(true) / sqrt($n);
}" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"><span style="color: #6A9955">/**</span></span>
<span class="line"><span style="color: #6A9955"> * Calculates the standard error of the mean (SEM) of the dataset.</span></span>
<span class="line"><span style="color: #6A9955"> *</span></span>
<span class="line"><span style="color: #6A9955"> * SEM = sample standard deviation / sqrt(n)</span></span>
<span class="line"><span style="color: #6A9955"> * Requires at least two observations.</span></span>
<span class="line"><span style="color: #6A9955"> *</span></span>
<span class="line"><span style="color: #6A9955"> * </span><span style="color: #569CD6">@throws</span><span style="color: #6A9955"> </span><span style="color: #4EC9B0">DomainException</span><span style="color: #6A9955"> If the dataset size is less than 2.</span></span>
<span class="line"><span style="color: #6A9955"> * </span><span style="color: #569CD6">@return</span><span style="color: #6A9955"> </span><span style="color: #569CD6">float</span><span style="color: #6A9955"> The standard error of the mean.</span></span>
<span class="line"><span style="color: #6A9955"> */</span></span>
<span class="line"><span style="color: #569CD6">public</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">function</span><span style="color: #D4D4D4"> </span><span style="color: #DCDCAA">standardError</span><span style="color: #D4D4D4">(): </span><span style="color: #569CD6">float</span></span>
<span class="line"><span style="color: #D4D4D4">{</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #9CDCFE">$n</span><span style="color: #D4D4D4"> = </span><span style="color: #DCDCAA">count</span><span style="color: #D4D4D4">(</span><span style="color: #569CD6">$this</span><span style="color: #D4D4D4">-&gt;</span><span style="color: #9CDCFE">data</span><span style="color: #D4D4D4">);</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #C586C0">if</span><span style="color: #D4D4D4"> (</span><span style="color: #9CDCFE">$n</span><span style="color: #D4D4D4"> &lt; </span><span style="color: #B5CEA8">2</span><span style="color: #D4D4D4">) {</span></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #C586C0">throw</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">new</span><span style="color: #D4D4D4"> </span><span style="color: #4EC9B0">DomainException</span><span style="color: #D4D4D4">(</span><span style="color: #CE9178">&#39;Standard error requires at least two observations.&#39;</span><span style="color: #D4D4D4">);</span></span>
<span class="line"><span style="color: #D4D4D4">    }</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #C586C0">return</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">$this</span><span style="color: #D4D4D4">-&gt;</span><span style="color: #DCDCAA">standardDeviation</span><span style="color: #D4D4D4">(</span><span style="color: #569CD6">true</span><span style="color: #D4D4D4">) / </span><span style="color: #DCDCAA">sqrt</span><span style="color: #D4D4D4">(</span><span style="color: #9CDCFE">$n</span><span style="color: #D4D4D4">);</span></span>
<span class="line"><span style="color: #D4D4D4">}</span></span></code></pre></div>



<p class="wp-block-paragraph"><br>Il metodo prende innanzitutto la dimensione del campione; se c’è un solo valore non ha senso parlare di errore standard, perciò viene sollevata un’eccezione di dominio. In tutti gli altri casi richiama la deviazione standard campionaria già implementata, ottenendo <img loading="lazy" decoding="async" src="https://renor.it/wp-content/ql-cache/quicklatex.com-ae1901659f469e6be883797bfd30f4f8_l3.png" class="ql-img-inline-formula quicklatex-auto-format" alt="&#115;" title="Rendered by QuickLaTeX.com" height="8" width="8" style="vertical-align: 0px;"/>. Dividendo <img loading="lazy" decoding="async" src="https://renor.it/wp-content/ql-cache/quicklatex.com-ae1901659f469e6be883797bfd30f4f8_l3.png" class="ql-img-inline-formula quicklatex-auto-format" alt="&#115;" title="Rendered by QuickLaTeX.com" height="8" width="8" style="vertical-align: 0px;"/> per la radice quadrata di n ricava il SEM secondo la definizione statistica canonica e restituisce il risultato come valore in virgola mobile. In questo modo tutta la logica numerica rimane coerente con le altre misure di dispersione: la funzione si appoggia a metodi collaudati, non replica calcoli già presenti e garantisce un contratto d’uso molto semplice.</p>



<h2 class="wp-block-heading">Scarto assoluto medio</h2>



<p class="wp-block-paragraph">Per misurare la dispersione in modo intuitivo, senza amplificare gli scarti con il quadrato come fa la varianza, si utilizza lo <strong>scarto assoluto medio</strong>. L’idea è semplice: si calcola la distanza assoluta fra ogni osservazione e la media aritmetica, poi si fa la media di quelle distanze. Se il campione è composto dai valori <img loading="lazy" decoding="async" src="https://renor.it/wp-content/ql-cache/quicklatex.com-5e8319f54f72e7dac2238515c1499b27_l3.png" class="ql-img-inline-formula quicklatex-auto-format" alt="&#120;&#95;&#49;&#44;&#32;&#120;&#95;&#50;&#44;&#32;&#92;&#100;&#111;&#116;&#115;&#44;&#32;&#120;&#95;&#110;" title="Rendered by QuickLaTeX.com" height="12" width="101" style="vertical-align: -4px;"/> e la loro media è <img loading="lazy" decoding="async" src="https://renor.it/wp-content/ql-cache/quicklatex.com-20ebc7ea21d727ebe3840c06a433ab09_l3.png" class="ql-img-inline-formula quicklatex-auto-format" alt="&#92;&#98;&#97;&#114;&#123;&#120;&#125;" title="Rendered by QuickLaTeX.com" height="11" width="10" style="vertical-align: 0px;"/>, lo scarto assoluto medio si ottiene con</p>



<p class="wp-block-paragraph"><img loading="lazy" decoding="async" src="https://renor.it/wp-content/ql-cache/quicklatex.com-851de72c318f9c4e22aa336e66091878_l3.png" class="ql-img-inline-formula quicklatex-auto-format" alt="&#92;&#116;&#101;&#120;&#116;&#123;&#77;&#65;&#68;&#125;&#32;&#92;&#59;&#61;&#92;&#59;&#32;&#92;&#102;&#114;&#97;&#99;&#123;&#49;&#125;&#123;&#110;&#125;&#92;&#115;&#117;&#109;&#95;&#123;&#105;&#61;&#49;&#125;&#94;&#123;&#110;&#125;&#32;&#92;&#108;&#118;&#101;&#114;&#116;&#32;&#120;&#95;&#105;&#32;&#45;&#32;&#92;&#98;&#97;&#114;&#123;&#120;&#125;&#32;&#92;&#114;&#118;&#101;&#114;&#116;" title="Rendered by QuickLaTeX.com" height="22" width="189" style="vertical-align: -6px;"/>.</p>



<p class="wp-block-paragraph">Lo scarto assoluto medio mantiene le stesse unità di misura dei dati, è meno sensibile agli outlier rispetto alla deviazione standard e offre un’interpretazione immediata: indica di quante unità, in media, ogni valore si discosta dal centro della distribuzione.</p>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#1E1E1E"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" data-code="/**
 * Calculates the mean absolute deviation (MAD) of the dataset.
 *
 * @return float The mean absolute deviation.
 */
public function meanAbsoluteDeviation(): float
{
    $mean = $this-&gt;mean();
    $sumAbs = 0.0;

    foreach ($this-&gt;data as $v) {
        $sumAbs += abs($v - $mean);
    }

    return $sumAbs / count($this-&gt;data);
}" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"><span style="color: #6A9955">/**</span></span>
<span class="line"><span style="color: #6A9955"> * Calculates the mean absolute deviation (MAD) of the dataset.</span></span>
<span class="line"><span style="color: #6A9955"> *</span></span>
<span class="line"><span style="color: #6A9955"> * </span><span style="color: #569CD6">@return</span><span style="color: #6A9955"> </span><span style="color: #569CD6">float</span><span style="color: #6A9955"> The mean absolute deviation.</span></span>
<span class="line"><span style="color: #6A9955"> */</span></span>
<span class="line"><span style="color: #569CD6">public</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">function</span><span style="color: #D4D4D4"> </span><span style="color: #DCDCAA">meanAbsoluteDeviation</span><span style="color: #D4D4D4">(): </span><span style="color: #569CD6">float</span></span>
<span class="line"><span style="color: #D4D4D4">{</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #9CDCFE">$mean</span><span style="color: #D4D4D4"> = </span><span style="color: #569CD6">$this</span><span style="color: #D4D4D4">-&gt;</span><span style="color: #DCDCAA">mean</span><span style="color: #D4D4D4">();</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #9CDCFE">$sumAbs</span><span style="color: #D4D4D4"> = </span><span style="color: #B5CEA8">0.0</span><span style="color: #D4D4D4">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #C586C0">foreach</span><span style="color: #D4D4D4"> (</span><span style="color: #569CD6">$this</span><span style="color: #D4D4D4">-&gt;</span><span style="color: #9CDCFE">data</span><span style="color: #D4D4D4"> as </span><span style="color: #9CDCFE">$v</span><span style="color: #D4D4D4">) {</span></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #9CDCFE">$sumAbs</span><span style="color: #D4D4D4"> += </span><span style="color: #DCDCAA">abs</span><span style="color: #D4D4D4">(</span><span style="color: #9CDCFE">$v</span><span style="color: #D4D4D4"> - </span><span style="color: #9CDCFE">$mean</span><span style="color: #D4D4D4">);</span></span>
<span class="line"><span style="color: #D4D4D4">    }</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #C586C0">return</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">$sumAbs</span><span style="color: #D4D4D4"> / </span><span style="color: #DCDCAA">count</span><span style="color: #D4D4D4">(</span><span style="color: #569CD6">$this</span><span style="color: #D4D4D4">-&gt;</span><span style="color: #9CDCFE">data</span><span style="color: #D4D4D4">);</span></span>
<span class="line"><span style="color: #D4D4D4">}</span></span></code></pre></div>



<p class="wp-block-paragraph"><br>Il metodo ricava innanzitutto la media aritmetica del campione tramite la funzione già esistente <code>mean()</code>. Con questa informazione scorre ogni osservazione, sottrae la media, prende il valore assoluto dello scarto e lo accumula in <code>$sumAbs</code>. Una volta terminato il ciclo divide la somma degli scarti assoluti per la numerosità del campione, restituendo il risultato in virgola mobile. La logica rimane lineare e senza rami condizionali perché la formula del MAD non richiede distinzioni tra popolazione e campione: vale sempre la divisione per <img loading="lazy" decoding="async" src="https://renor.it/wp-content/ql-cache/quicklatex.com-b170995d512c659d8668b4e42e1fef6b_l3.png" class="ql-img-inline-formula quicklatex-auto-format" alt="&#110;" title="Rendered by QuickLaTeX.com" height="8" width="11" style="vertical-align: 0px;"/>.</p>



<h2 class="wp-block-heading">Percentili</h2>



<p class="wp-block-paragraph">Per localizzare un valore qualsiasi lungo la distribuzione si utilizzano i <strong>percentili</strong>: il percentile <img loading="lazy" decoding="async" src="https://renor.it/wp-content/ql-cache/quicklatex.com-3bf85f1087e9fbed3a319341134ac1a2_l3.png" class="ql-img-inline-formula quicklatex-auto-format" alt="&#112;" title="Rendered by QuickLaTeX.com" height="12" width="10" style="vertical-align: -4px;"/> individua il punto sotto il quale ricade esattamente la percentuale <img loading="lazy" decoding="async" src="https://renor.it/wp-content/ql-cache/quicklatex.com-99e832fcda204df594c5836eadfc494f_l3.png" class="ql-img-inline-formula quicklatex-auto-format" alt="&#112;&#44;&#37;" title="Rendered by QuickLaTeX.com" height="12" width="14" style="vertical-align: -4px;"/> dei dati ordinati. Il 50° percentile coincide con la mediana, il 25° e il 75° formano i quartili già implementati e, in generale, conoscere più percentili permette di descrivere la forma della distribuzione in maniera molto dettagliata. Poiché il campione è finito, la posizione del percentile raramente coincide con un indice intero: occorre dunque interpolare fra gli elementi adiacenti. Una convenzione ampiamente adottata (Excel e NumPy “linear” method) consiste nel calcolare</p>



<p class="wp-block-paragraph"><img loading="lazy" decoding="async" src="https://renor.it/wp-content/ql-cache/quicklatex.com-abfa90ac6a2818ca37cc2160c0eda4d0_l3.png" class="ql-img-inline-formula quicklatex-auto-format" alt="&#114;&#32;&#61;&#32;&#92;&#102;&#114;&#97;&#99;&#123;&#112;&#125;&#123;&#49;&#48;&#48;&#125;&#92;&#44;&#40;&#110;&#45;&#49;&#41;" title="Rendered by QuickLaTeX.com" height="20" width="114" style="vertical-align: -6px;"/></p>



<p class="wp-block-paragraph">dove <img loading="lazy" decoding="async" src="https://renor.it/wp-content/ql-cache/quicklatex.com-b170995d512c659d8668b4e42e1fef6b_l3.png" class="ql-img-inline-formula quicklatex-auto-format" alt="&#110;" title="Rendered by QuickLaTeX.com" height="8" width="11" style="vertical-align: 0px;"/> è la numerosità: se r cade fra gli indici <img loading="lazy" decoding="async" src="https://renor.it/wp-content/ql-cache/quicklatex.com-3422b6bb5c160593658b7c39425d9880_l3.png" class="ql-img-inline-formula quicklatex-auto-format" alt="&#107;" title="Rendered by QuickLaTeX.com" height="12" width="9" style="vertical-align: 0px;"/> e <img loading="lazy" decoding="async" src="https://renor.it/wp-content/ql-cache/quicklatex.com-1e22674f5099474b9902f53541dfc8dc_l3.png" class="ql-img-inline-formula quicklatex-auto-format" alt="&#107;&#43;&#49;" title="Rendered by QuickLaTeX.com" height="14" width="39" style="vertical-align: -2px;"/>, il percentile è la combinazione lineare dei due valori con peso uguale alla parte frazionaria di <img loading="lazy" decoding="async" src="https://renor.it/wp-content/ql-cache/quicklatex.com-c409433a9e2dfcdb83360a974d243f18_l3.png" class="ql-img-inline-formula quicklatex-auto-format" alt="&#114;" title="Rendered by QuickLaTeX.com" height="8" width="8" style="vertical-align: 0px;"/>.</p>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#1E1E1E"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" data-code="/**
 * Returns the p-th percentile of the dataset (linear interpolation).
 *
 * @param float $p Percentile in the closed range [0, 100].
 * @throws DomainException If $p is outside 0–100.
 * @return float The requested percentile.
 */
public function percentile(float $p): float
{
    if ($p &lt; 0.0 || $p &gt; 100.0) {
        throw new DomainException('Percentile must be between 0 and 100.');
    }

    $sorted = $this-&gt;data;
    sort($sorted, SORT_NUMERIC);
    $n = count($sorted);

    // Edge cases: 0th and 100th percentile
    if ($p === 0.0)   { return (float) $sorted[0]; }
    if ($p === 100.0) { return (float) $sorted[$n - 1]; }

    // Linear-interpolated rank
    $rank        = ($p / 100.0) * ($n - 1);
    $lowerIndex  = (int) floor($rank);
    $upperIndex  = (int) ceil($rank);
    $weightUpper = $rank - $lowerIndex;

    // If rank is an integer, no interpolation is needed
    if ($lowerIndex === $upperIndex) {
        return (float) $sorted[$lowerIndex];
    }

    $lowerValue = $sorted[$lowerIndex];
    $upperValue = $sorted[$upperIndex];

    return (1.0 - $weightUpper) * $lowerValue + $weightUpper * $upperValue;
}" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"><span style="color: #6A9955">/**</span></span>
<span class="line"><span style="color: #6A9955"> * Returns the p-th percentile of the dataset (linear interpolation).</span></span>
<span class="line"><span style="color: #6A9955"> *</span></span>
<span class="line"><span style="color: #6A9955"> * </span><span style="color: #569CD6">@param</span><span style="color: #6A9955"> </span><span style="color: #569CD6">float</span><span style="color: #6A9955"> $p Percentile in the closed range [0, 100].</span></span>
<span class="line"><span style="color: #6A9955"> * </span><span style="color: #569CD6">@throws</span><span style="color: #6A9955"> </span><span style="color: #4EC9B0">DomainException</span><span style="color: #6A9955"> If $p is outside 0–100.</span></span>
<span class="line"><span style="color: #6A9955"> * </span><span style="color: #569CD6">@return</span><span style="color: #6A9955"> </span><span style="color: #569CD6">float</span><span style="color: #6A9955"> The requested percentile.</span></span>
<span class="line"><span style="color: #6A9955"> */</span></span>
<span class="line"><span style="color: #569CD6">public</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">function</span><span style="color: #D4D4D4"> </span><span style="color: #DCDCAA">percentile</span><span style="color: #D4D4D4">(</span><span style="color: #569CD6">float</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">$p</span><span style="color: #D4D4D4">): </span><span style="color: #569CD6">float</span></span>
<span class="line"><span style="color: #D4D4D4">{</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #C586C0">if</span><span style="color: #D4D4D4"> (</span><span style="color: #9CDCFE">$p</span><span style="color: #D4D4D4"> &lt; </span><span style="color: #B5CEA8">0.0</span><span style="color: #D4D4D4"> || </span><span style="color: #9CDCFE">$p</span><span style="color: #D4D4D4"> &gt; </span><span style="color: #B5CEA8">100.0</span><span style="color: #D4D4D4">) {</span></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #C586C0">throw</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">new</span><span style="color: #D4D4D4"> </span><span style="color: #4EC9B0">DomainException</span><span style="color: #D4D4D4">(</span><span style="color: #CE9178">&#39;Percentile must be between 0 and 100.&#39;</span><span style="color: #D4D4D4">);</span></span>
<span class="line"><span style="color: #D4D4D4">    }</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #9CDCFE">$sorted</span><span style="color: #D4D4D4"> = </span><span style="color: #569CD6">$this</span><span style="color: #D4D4D4">-&gt;</span><span style="color: #9CDCFE">data</span><span style="color: #D4D4D4">;</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #DCDCAA">sort</span><span style="color: #D4D4D4">(</span><span style="color: #9CDCFE">$sorted</span><span style="color: #D4D4D4">, SORT_NUMERIC);</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #9CDCFE">$n</span><span style="color: #D4D4D4"> = </span><span style="color: #DCDCAA">count</span><span style="color: #D4D4D4">(</span><span style="color: #9CDCFE">$sorted</span><span style="color: #D4D4D4">);</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #6A9955">// Edge cases: 0th and 100th percentile</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #C586C0">if</span><span style="color: #D4D4D4"> (</span><span style="color: #9CDCFE">$p</span><span style="color: #D4D4D4"> === </span><span style="color: #B5CEA8">0.0</span><span style="color: #D4D4D4">)   { </span><span style="color: #C586C0">return</span><span style="color: #D4D4D4"> (</span><span style="color: #569CD6">float</span><span style="color: #D4D4D4">) </span><span style="color: #9CDCFE">$sorted</span><span style="color: #D4D4D4">[</span><span style="color: #B5CEA8">0</span><span style="color: #D4D4D4">]; }</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #C586C0">if</span><span style="color: #D4D4D4"> (</span><span style="color: #9CDCFE">$p</span><span style="color: #D4D4D4"> === </span><span style="color: #B5CEA8">100.0</span><span style="color: #D4D4D4">) { </span><span style="color: #C586C0">return</span><span style="color: #D4D4D4"> (</span><span style="color: #569CD6">float</span><span style="color: #D4D4D4">) </span><span style="color: #9CDCFE">$sorted</span><span style="color: #D4D4D4">[</span><span style="color: #9CDCFE">$n</span><span style="color: #D4D4D4"> - </span><span style="color: #B5CEA8">1</span><span style="color: #D4D4D4">]; }</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #6A9955">// Linear-interpolated rank</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #9CDCFE">$rank</span><span style="color: #D4D4D4">        = (</span><span style="color: #9CDCFE">$p</span><span style="color: #D4D4D4"> / </span><span style="color: #B5CEA8">100.0</span><span style="color: #D4D4D4">) * (</span><span style="color: #9CDCFE">$n</span><span style="color: #D4D4D4"> - </span><span style="color: #B5CEA8">1</span><span style="color: #D4D4D4">);</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #9CDCFE">$lowerIndex</span><span style="color: #D4D4D4">  = (</span><span style="color: #569CD6">int</span><span style="color: #D4D4D4">) </span><span style="color: #DCDCAA">floor</span><span style="color: #D4D4D4">(</span><span style="color: #9CDCFE">$rank</span><span style="color: #D4D4D4">);</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #9CDCFE">$upperIndex</span><span style="color: #D4D4D4">  = (</span><span style="color: #569CD6">int</span><span style="color: #D4D4D4">) </span><span style="color: #DCDCAA">ceil</span><span style="color: #D4D4D4">(</span><span style="color: #9CDCFE">$rank</span><span style="color: #D4D4D4">);</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #9CDCFE">$weightUpper</span><span style="color: #D4D4D4"> = </span><span style="color: #9CDCFE">$rank</span><span style="color: #D4D4D4"> - </span><span style="color: #9CDCFE">$lowerIndex</span><span style="color: #D4D4D4">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #6A9955">// If rank is an integer, no interpolation is needed</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #C586C0">if</span><span style="color: #D4D4D4"> (</span><span style="color: #9CDCFE">$lowerIndex</span><span style="color: #D4D4D4"> === </span><span style="color: #9CDCFE">$upperIndex</span><span style="color: #D4D4D4">) {</span></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #C586C0">return</span><span style="color: #D4D4D4"> (</span><span style="color: #569CD6">float</span><span style="color: #D4D4D4">) </span><span style="color: #9CDCFE">$sorted</span><span style="color: #D4D4D4">[</span><span style="color: #9CDCFE">$lowerIndex</span><span style="color: #D4D4D4">];</span></span>
<span class="line"><span style="color: #D4D4D4">    }</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #9CDCFE">$lowerValue</span><span style="color: #D4D4D4"> = </span><span style="color: #9CDCFE">$sorted</span><span style="color: #D4D4D4">[</span><span style="color: #9CDCFE">$lowerIndex</span><span style="color: #D4D4D4">];</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #9CDCFE">$upperValue</span><span style="color: #D4D4D4"> = </span><span style="color: #9CDCFE">$sorted</span><span style="color: #D4D4D4">[</span><span style="color: #9CDCFE">$upperIndex</span><span style="color: #D4D4D4">];</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #C586C0">return</span><span style="color: #D4D4D4"> (</span><span style="color: #B5CEA8">1.0</span><span style="color: #D4D4D4"> - </span><span style="color: #9CDCFE">$weightUpper</span><span style="color: #D4D4D4">) * </span><span style="color: #9CDCFE">$lowerValue</span><span style="color: #D4D4D4"> + </span><span style="color: #9CDCFE">$weightUpper</span><span style="color: #D4D4D4"> * </span><span style="color: #9CDCFE">$upperValue</span><span style="color: #D4D4D4">;</span></span>
<span class="line"><span style="color: #D4D4D4">}</span></span></code></pre></div>



<p class="wp-block-paragraph"><br>Il metodo convalida innanzitutto che il percentile richiesto sia compreso fra 0 e 100 inclusi, garantendo così coerenza con la definizione statistica. Subito dopo crea una copia ordinata dei dati, perché qualsiasi localizzazione percentuale richiede il vettore monotònicamente crescente. Gli estremi 0 e 100 vengono gestiti esplicitamente restituendo rispettivamente il minimo e il massimo del campione. Per tutti gli altri valori si calcola il rango reale <img loading="lazy" decoding="async" src="https://renor.it/wp-content/ql-cache/quicklatex.com-c409433a9e2dfcdb83360a974d243f18_l3.png" class="ql-img-inline-formula quicklatex-auto-format" alt="&#114;" title="Rendered by QuickLaTeX.com" height="8" width="8" style="vertical-align: 0px;"/>, che può cadere fra due indici interi; l’indice inferiore e quello superiore delimitano l’intervallo che contiene la posizione frazionaria. Se <img loading="lazy" decoding="async" src="https://renor.it/wp-content/ql-cache/quicklatex.com-c409433a9e2dfcdb83360a974d243f18_l3.png" class="ql-img-inline-formula quicklatex-auto-format" alt="&#114;" title="Rendered by QuickLaTeX.com" height="8" width="8" style="vertical-align: 0px;"/> è già intero non serve interpolazione e il metodo restituisce direttamente l’elemento corrispondente. In caso contrario si combinano linearmente il valore inferiore e quello superiore con un peso uguale alla parte decimale di <img loading="lazy" decoding="async" src="https://renor.it/wp-content/ql-cache/quicklatex.com-c409433a9e2dfcdb83360a974d243f18_l3.png" class="ql-img-inline-formula quicklatex-auto-format" alt="&#114;" title="Rendered by QuickLaTeX.com" height="8" width="8" style="vertical-align: 0px;"/>, producendo un risultato continuo che scorre uniformemente fra gli elementi del campione.</p>



<h2 class="wp-block-heading">Minimo e Massimo</h2>



<p class="wp-block-paragraph"><br>Per completare il quadro delle misure descrittive è utile poter recuperare rapidamente l’estremo inferiore e quello superiore della distribuzione. Il <strong>valore minimo</strong> indica l’osservazione più piccola registrata nel campione; il <strong>valore massimo</strong> segnala la più grande. Queste due grandezze, pur estremamente semplici, sono indispensabili sia per dare il contesto ai dati (sapere dove inizia e dove finisce l’intervallo effettivamente osservato) sia come ingrediente di altre statistiche, ad esempio il range che hai già implementato. Poiché il dataset è interamente in memoria, individuare minimo e massimo richiede una sola scansione lineare e il costo computazionale è trascurabile.</p>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#1E1E1E"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" data-code="/**
 * Returns the minimum value of the dataset.
 *
 * @return float The smallest observation.
 */
public function minValue(): float
{
    return (float) min($this-&gt;data);
}

/**
 * Returns the maximum value of the dataset.
 *
 * @return float The largest observation.
 */
public function maxValue(): float
{
    return (float) max($this-&gt;data);
}" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"><span style="color: #6A9955">/**</span></span>
<span class="line"><span style="color: #6A9955"> * Returns the minimum value of the dataset.</span></span>
<span class="line"><span style="color: #6A9955"> *</span></span>
<span class="line"><span style="color: #6A9955"> * </span><span style="color: #569CD6">@return</span><span style="color: #6A9955"> </span><span style="color: #569CD6">float</span><span style="color: #6A9955"> The smallest observation.</span></span>
<span class="line"><span style="color: #6A9955"> */</span></span>
<span class="line"><span style="color: #569CD6">public</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">function</span><span style="color: #D4D4D4"> </span><span style="color: #DCDCAA">minValue</span><span style="color: #D4D4D4">(): </span><span style="color: #569CD6">float</span></span>
<span class="line"><span style="color: #D4D4D4">{</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #C586C0">return</span><span style="color: #D4D4D4"> (</span><span style="color: #569CD6">float</span><span style="color: #D4D4D4">) </span><span style="color: #DCDCAA">min</span><span style="color: #D4D4D4">(</span><span style="color: #569CD6">$this</span><span style="color: #D4D4D4">-&gt;</span><span style="color: #9CDCFE">data</span><span style="color: #D4D4D4">);</span></span>
<span class="line"><span style="color: #D4D4D4">}</span></span>
<span class="line"></span>
<span class="line"><span style="color: #6A9955">/**</span></span>
<span class="line"><span style="color: #6A9955"> * Returns the maximum value of the dataset.</span></span>
<span class="line"><span style="color: #6A9955"> *</span></span>
<span class="line"><span style="color: #6A9955"> * </span><span style="color: #569CD6">@return</span><span style="color: #6A9955"> </span><span style="color: #569CD6">float</span><span style="color: #6A9955"> The largest observation.</span></span>
<span class="line"><span style="color: #6A9955"> */</span></span>
<span class="line"><span style="color: #569CD6">public</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">function</span><span style="color: #D4D4D4"> </span><span style="color: #DCDCAA">maxValue</span><span style="color: #D4D4D4">(): </span><span style="color: #569CD6">float</span></span>
<span class="line"><span style="color: #D4D4D4">{</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #C586C0">return</span><span style="color: #D4D4D4"> (</span><span style="color: #569CD6">float</span><span style="color: #D4D4D4">) </span><span style="color: #DCDCAA">max</span><span style="color: #D4D4D4">(</span><span style="color: #569CD6">$this</span><span style="color: #D4D4D4">-&gt;</span><span style="color: #9CDCFE">data</span><span style="color: #D4D4D4">);</span></span>
<span class="line"><span style="color: #D4D4D4">}</span></span></code></pre></div>



<p class="wp-block-paragraph"><br>Le funzioni PHP min() e max() attraversano l’array una sola volta; il cast garantisce che il tipo restituito sia float, uniforme con il resto dell’API.</p>



<h2 class="wp-block-heading">Conclusioni</h2>



<p class="wp-block-paragraph">Con questo ultimo metodo abbiamo completato la nostra Classe <code>DescriptiveStats</code> che ora racchiude in un unico componente i più importanti strumenti di statistica descrittiva: dalle misure di posizione (media aritmetica, mediana, moda, percentili) alle misure di dispersione (range, varianza, deviazione standard, IQR, MAD), passando per indicatori di robustezza (media troncata) e incertezza (errore standard). Ogni funzione è autonoma, tipizzata e corredata di test automatici con PHPUnit che non abbiamo riportato per non allungare ulteriormente questo articolo già abbastanza pregno di nozioni. </p>



<p class="wp-block-paragraph">Grazie a questa libreria, un progetto PHP può analizzare rapidamente piccoli dataset senza dipendenze esterne e senza dover utilizzare l&#8217;intelligenza artificiale solo per &#8220;moda&#8221;, integrare calcoli statistici in report, dashboard o API, estendere la classe con ulteriori indicatori sfruttando un&#8217;architettura chiara e coerente. </p>



<p class="wp-block-paragraph">Nel prossimo articolo vedremo come trasformare il codice in un pacchetto Composer: creeremo la struttura definitiva della repository, vedremo come modificare il file <code>composer.json</code>, configureremo la CI per eseguire i test e pubblicheremo la libreria su Packagist, rendendola installabile con un semplice:</p>



<p class="wp-block-paragraph"><code>composer require thesimon82/descriptive-statistics</code></p>



<p class="wp-block-paragraph">In questo modo potrai distribuire la tua soluzione open-source, ricevere contributi dalla community e riutilizzarla in qualsiasi progetto con la massima semplicità.</p>



<p class="wp-block-paragraph">[starbox]</p>
<p>L'articolo <a href="https://renor.it/blog/sviluppo-software-programmazione/una-classe-di-statistica-descrittiva-in-php/">Una Classe di Statistica descrittiva in PHP</a> proviene da <a href="https://renor.it">RENOR &amp; Partners S.r.l.</a>.</p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Watermark Invisibile in JPEG con PHP 8</title>
		<link>https://renor.it/blog/sviluppo-software-programmazione/watermark-invisibile-in-jpeg-con-php-8/</link>
		
		<dc:creator><![CDATA[Simone Renzi]]></dc:creator>
		<pubDate>Sun, 11 May 2025 04:27:30 +0000</pubDate>
				<category><![CDATA[Sviluppo Software & Programmazione]]></category>
		<category><![CDATA[blog fotografico]]></category>
		<category><![CDATA[compressione jpeg]]></category>
		<category><![CDATA[copyright]]></category>
		<category><![CDATA[dct]]></category>
		<category><![CDATA[firma digitale]]></category>
		<category><![CDATA[fotografia digitale]]></category>
		<category><![CDATA[gd]]></category>
		<category><![CDATA[imagick]]></category>
		<category><![CDATA[jpeg]]></category>
		<category><![CDATA[metadata invisibili]]></category>
		<category><![CDATA[open source]]></category>
		<category><![CDATA[php]]></category>
		<category><![CDATA[protezione immagini]]></category>
		<category><![CDATA[script php]]></category>
		<category><![CDATA[sicurezza immagini]]></category>
		<category><![CDATA[steganografia]]></category>
		<category><![CDATA[trasformata coseno discreta]]></category>
		<category><![CDATA[watermark invisibile]]></category>
		<category><![CDATA[watermarking robusto]]></category>
		<guid isPermaLink="false">https://renor.it/?p=334</guid>

					<description><![CDATA[<p>Watermark invisibile nei JPEG con PHP 8: incorpora una firma nascosta nei coefficienti DCT per proteggere le immagini senza rovinarle, codice open source.</p>
<p>L'articolo <a href="https://renor.it/blog/sviluppo-software-programmazione/watermark-invisibile-in-jpeg-con-php-8/">Watermark Invisibile in JPEG con PHP 8</a> proviene da <a href="https://renor.it">RENOR &amp; Partners S.r.l.</a>.</p>
]]></description>
										<content:encoded><![CDATA[<style>.renor-latex-display{max-width:100%;overflow-x:auto}.renor-latex-display>.ql-center-displayed-equation{overflow:visible!important;min-width:max-content}</style>
<h2 class="wp-block-heading">Proteggi le tue immagini modificando i coefficienti, senza rovinarle</h2>
<p>Pubblicare fotografie online è diventato indispensabile per fotografi, e-commerce e blogger, ma secondo gli studi più recenti sul furto d&#8217;immagini, oltre il 70% dei contenuti visivi viene ricondiviso senza credito o autorizzazione. Una filigrana visibile protegge certamente l&#8217;autore, ma per renderla effettivamente valida ai fini del furto della proprietà intellettuale, spesso rovina l&#8217;estetica dello scatto con una &#8220;pecetta&#8221; tutt&#8217;altro che piacevole!</p>
<p>Al contrario, un watermark “invisibile” inscritto nei coefficienti della Trasformata Coseno Discreta (DCT), su cui si basa il formato JPEG, preserva la qualità percepita e può resistere a ridimensionamenti o compressioni leggere.</p>
<p>Codificando l’informazione nel <strong>segno</strong> di specifici coefficienti a bassa frequenza, è possibile garantire un compromesso efficace tra invisibilità e robustezza.</p>
<p>In questo progetto open-source, disponibile nella mia repository GitHub: <a href="https://github.com/thesimon82/php-dct-invisible-watermark">https://github.com/thesimon82/php-dct-invisible-watermark</a>, scritto in PHP 8.3 e basato su GD/Imagick per la manipolazione dei pixel, mostreremo passo passo come incorporare una firma testuale nei coefficienti a bassa frequenza (AC) di ciascun blocco 8×8, come recuperarne l’impronta e perché il <strong>segno del coefficiente</strong> rappresenta una strategia robusta contro le comuni compressioni JPEG, anche a qualità 80% o inferiore.</p>
<p>L’obiettivo non è solo didattico: il micro-servizio risultante può essere clonato dal repository e integrato, via CLI o API, in qualunque workflow di pubblicazione immagini.</p>
<h2 class="wp-block-heading">I fondamenti tecnici</h2>
<p>Prima di scrivere una sola riga di codice conviene chiarire come l&#8217;algoritmo di compressione JPEG agisce sulle immagini che deve comprimere.</p>
<p>Il formato JPEG divide l’immagine in una griglia di blocchi 8×8 pixel; ciascun blocco viene trasformato tramite la Discrete Cosine Transform (DCT), che scompone l’informazione visiva in 64 coefficienti ordinati dalla frequenza più bassa (l’angolo in alto a sinistra, responsabile dell’intensità media) a quella più alta (i dettagli più fini).</p>
<p>I coefficienti a media-bassa frequenza sono il punto ideale per il nostro watermark: toccare il coefficiente a frequenza zero (DC) produrrebbe aloni visibili, mentre alterare solo le frequenze più alte porterebbe a una loro eliminazione già alla prima compressione JPEG.</p>
<p>Intervenendo invece su coefficienti intermedi possiamo codificare singoli bit <strong>modificando il segno del coefficiente</strong> (positivo = 0, negativo = 1), ottenendo così un marcatore invisibile all’occhio ma sufficientemente robusto da sopravvivere a ridimensionamenti e compressioni JPEG fino a qualità 80.</p>
<p>Questo principio matematico guiderà l’intera implementazione.</p>
<p>Leggeremo ogni blocco 8×8, calcoleremo la DCT tramite una funzione nativa in PHP, modificheremo il <strong>segno</strong> di uno o più coefficienti scelti e salveremo il nuovo JPEG tramite GD o Imagick.</p>
<p>In altre parole, il watermark sarà nascosto proprio nei coefficienti che l’algoritmo di compressione JPEG tende a preservare: sarà invisibile all’occhio ma difficile da rimuovere, anche in presenza di ricompressioni leggere.</p>
<h2 class="wp-block-heading">La matematica che rende invisibile il watermark</h2>
<p>Ogni blocco <img loading="lazy" decoding="async" src="https://renor.it/wp-content/ql-cache/quicklatex.com-30c8c8360c9567083495da77371411fc_l3.png" class="ql-img-inline-formula quicklatex-auto-format" alt="&#56;&#32;&#92;&#116;&#105;&#109;&#101;&#115;&#32;&#56;" title="Rendered by QuickLaTeX.com" height="12" width="40" style="vertical-align: 0px;"/> di intensità <img loading="lazy" decoding="async" src="https://renor.it/wp-content/ql-cache/quicklatex.com-533196a0d71c414a47d0753600045b35_l3.png" class="ql-img-inline-formula quicklatex-auto-format" alt="&#102;&#95;&#123;&#120;&#44;&#121;&#125;" title="Rendered by QuickLaTeX.com" height="18" width="28" style="vertical-align: -6px;"/> (dove <img loading="lazy" decoding="async" src="https://renor.it/wp-content/ql-cache/quicklatex.com-45b8ab0d4da19f0c0f1a6c669aed973d_l3.png" class="ql-img-inline-formula quicklatex-auto-format" alt="&#120;&#44;&#121;&#32;&#92;&#105;&#110;&#32;&#92;&#123;&#48;&#44;&#92;&#100;&#111;&#116;&#115;&#44;&#55;&#92;&#125;" title="Rendered by QuickLaTeX.com" height="19" width="123" style="vertical-align: -5px;"/>) viene convertito in 64 coefficienti <img loading="lazy" decoding="async" src="https://renor.it/wp-content/ql-cache/quicklatex.com-c82f152c8e6619cbeddd318d16e9aa3c_l3.png" class="ql-img-inline-formula quicklatex-auto-format" alt="&#67;&#95;&#123;&#117;&#44;&#118;&#125;" title="Rendered by QuickLaTeX.com" height="18" width="32" style="vertical-align: -6px;"/> (con <img loading="lazy" decoding="async" src="https://renor.it/wp-content/ql-cache/quicklatex.com-3568fd28364bcfd7b6e3a22d1242fb48_l3.png" class="ql-img-inline-formula quicklatex-auto-format" alt="&#117;&#44;&#118;&#32;&#92;&#105;&#110;&#32;&#92;&#123;&#48;&#44;&#92;&#100;&#111;&#116;&#115;&#44;&#55;&#92;&#125;" title="Rendered by QuickLaTeX.com" height="19" width="123" style="vertical-align: -5px;"/>) tramite:</p>
<div class="renor-latex-display"><p class="ql-center-displayed-equation" style="line-height: 55px;"><span class="ql-right-eqno"> (1) </span><span class="ql-left-eqno"> &nbsp; </span><img loading="lazy" decoding="async" src="https://renor.it/wp-content/ql-cache/quicklatex.com-e35bc49a02ed85ff8439bfd88c5549b2_l3.png" height="55" width="510" class="ql-img-displayed-equation quicklatex-auto-format" alt="&#92;&#98;&#101;&#103;&#105;&#110;&#123;&#100;&#105;&#115;&#112;&#108;&#97;&#121;&#109;&#97;&#116;&#104;&#125; &#67;&#95;&#123;&#117;&#44;&#118;&#125;&#61;&#92;&#102;&#114;&#97;&#99;&#123;&#49;&#125;&#123;&#52;&#125;&#92;&#44;&#92;&#97;&#108;&#112;&#104;&#97;&#40;&#117;&#41;&#92;&#44;&#92;&#97;&#108;&#112;&#104;&#97;&#40;&#118;&#41; &#92;&#115;&#117;&#109;&#95;&#123;&#120;&#61;&#48;&#125;&#94;&#123;&#55;&#125;&#92;&#115;&#117;&#109;&#95;&#123;&#121;&#61;&#48;&#125;&#94;&#123;&#55;&#125;&#32;&#102;&#95;&#123;&#120;&#44;&#121;&#125; &#92;&#99;&#111;&#115;&#92;&#33;&#92;&#108;&#101;&#102;&#116;&#40;&#92;&#102;&#114;&#97;&#99;&#123;&#40;&#50;&#120;&#43;&#49;&#41;&#117;&#92;&#112;&#105;&#125;&#123;&#49;&#54;&#125;&#92;&#114;&#105;&#103;&#104;&#116;&#41; &#92;&#99;&#111;&#115;&#92;&#33;&#92;&#108;&#101;&#102;&#116;&#40;&#92;&#102;&#114;&#97;&#99;&#123;&#40;&#50;&#121;&#43;&#49;&#41;&#118;&#92;&#112;&#105;&#125;&#123;&#49;&#54;&#125;&#92;&#114;&#105;&#103;&#104;&#116;&#41; &#92;&#101;&#110;&#100;&#123;&#100;&#105;&#115;&#112;&#108;&#97;&#121;&#109;&#97;&#116;&#104;&#125;" title="Rendered by QuickLaTeX.com"/></p></div>
<p> </p>
<p>dove</p>
<div class="renor-latex-display"><p class="ql-center-displayed-equation" style="line-height: 66px;"><span class="ql-right-eqno"> &nbsp; </span><span class="ql-left-eqno"> &nbsp; </span><img loading="lazy" decoding="async" src="https://renor.it/wp-content/ql-cache/quicklatex.com-4d8ed69ee5a88099633a20c117e339c7_l3.png" height="66" width="171" class="ql-img-displayed-equation quicklatex-auto-format" alt="&#92;&#98;&#101;&#103;&#105;&#110;&#123;&#100;&#105;&#115;&#112;&#108;&#97;&#121;&#109;&#97;&#116;&#104;&#125; &#92;&#97;&#108;&#112;&#104;&#97;&#40;&#107;&#41;&#61; &#92;&#98;&#101;&#103;&#105;&#110;&#123;&#99;&#97;&#115;&#101;&#115;&#125; &#92;&#100;&#102;&#114;&#97;&#99;&#123;&#49;&#125;&#123;&#92;&#115;&#113;&#114;&#116;&#123;&#50;&#125;&#125;&#44;&#32;&#38;&#32;&#107;&#61;&#48;&#44;&#92;&#92;&#91;&#54;&#112;&#116;&#93; &#49;&#44;&#32;&#38;&#32;&#107;&#92;&#103;&#101;&#32;&#49;&#46; &#92;&#101;&#110;&#100;&#123;&#99;&#97;&#115;&#101;&#115;&#125; &#92;&#101;&#110;&#100;&#123;&#100;&#105;&#115;&#112;&#108;&#97;&#121;&#109;&#97;&#116;&#104;&#125;" title="Rendered by QuickLaTeX.com"/></p></div>
<p><img loading="lazy" decoding="async" src="https://renor.it/wp-content/ql-cache/quicklatex.com-d28eb1caf4d0c1c6fad49a76dcf1fcd7_l3.png" class="ql-img-inline-formula quicklatex-auto-format" alt="&#67;&#95;&#123;&#48;&#44;&#48;&#125;" title="Rendered by QuickLaTeX.com" height="18" width="31" style="vertical-align: -6px;"/> (coefficiente DC) è la media luminosa del blocco. I coefficienti<b>AC</b><img loading="lazy" decoding="async" src="https://renor.it/wp-content/ql-cache/quicklatex.com-a294e0d74e5dd50afac4f10b516f23e8_l3.png" class="ql-img-inline-formula quicklatex-auto-format" alt="&#40;&#117;&#44;&#118;&#41;&#92;&#110;&#101;&#113;&#40;&#48;&#44;&#48;&#41;" title="Rendered by QuickLaTeX.com" height="19" width="102" style="vertical-align: -5px;"/> descrivono contenuti sempre più fini man mano che <img loading="lazy" decoding="async" src="https://renor.it/wp-content/ql-cache/quicklatex.com-43fe27dc3e528266a619764d90fce60b_l3.png" class="ql-img-inline-formula quicklatex-auto-format" alt="&#117;" title="Rendered by QuickLaTeX.com" height="8" width="10" style="vertical-align: 0px;"/> o <img loading="lazy" decoding="async" src="https://renor.it/wp-content/ql-cache/quicklatex.com-ef71511c70f0e4b25cc6bd69f3bc20c2_l3.png" class="ql-img-inline-formula quicklatex-auto-format" alt="&#118;" title="Rendered by QuickLaTeX.com" height="8" width="9" style="vertical-align: 0px;"/> crescono.</p>
<h3 class="wp-block-heading">Esempio numerico semplificato</h3>
<p>Supponiamo un blocco che abbia tutto un valore di 128, un grigio medio. Allora:</p>
<p><img loading="lazy" decoding="async" src="https://renor.it/wp-content/ql-cache/quicklatex.com-ec6eea47d23bf7a9ad7231876b45fad8_l3.png" class="ql-img-inline-formula quicklatex-auto-format" alt="&#67;&#95;&#123;&#48;&#44;&#48;&#125;&#61;&#56;&#92;&#99;&#100;&#111;&#116;&#56;&#92;&#99;&#100;&#111;&#116;&#49;&#50;&#56;&#92;&#99;&#100;&#111;&#116;&#92;&#102;&#114;&#97;&#99;&#123;&#49;&#125;&#123;&#52;&#125;&#92;&#97;&#108;&#112;&#104;&#97;&#40;&#48;&#41;&#94;&#50;&#61;&#54;&#52;&#92;&#99;&#100;&#111;&#116;&#49;&#50;&#56;&#92;&#99;&#100;&#111;&#116;&#92;&#102;&#114;&#97;&#99;&#123;&#49;&#125;&#123;&#52;&#125;&#92;&#99;&#100;&#111;&#116;&#92;&#102;&#114;&#97;&#99;&#123;&#49;&#125;&#123;&#50;&#125;&#61;&#49;&#48;&#50;&#52;" title="Rendered by QuickLaTeX.com" height="22" width="377" style="vertical-align: -6px;"/>, mentre <img loading="lazy" decoding="async" src="https://renor.it/wp-content/ql-cache/quicklatex.com-173279858d8b2982ad84681cdf99b8d8_l3.png" class="ql-img-inline-formula quicklatex-auto-format" alt="&#67;&#95;&#123;&#117;&#44;&#118;&#125;&#61;&#48;" title="Rendered by QuickLaTeX.com" height="18" width="65" style="vertical-align: -6px;"/> per <img loading="lazy" decoding="async" src="https://renor.it/wp-content/ql-cache/quicklatex.com-a294e0d74e5dd50afac4f10b516f23e8_l3.png" class="ql-img-inline-formula quicklatex-auto-format" alt="&#40;&#117;&#44;&#118;&#41;&#92;&#110;&#101;&#113;&#40;&#48;&#44;&#48;&#41;" title="Rendered by QuickLaTeX.com" height="19" width="102" style="vertical-align: -5px;"/> perché non ci sono variazioni di frequenza.</p>
<p>L&#8217;immagine compressa conserva i coefficienti più bassi, quelli più alti sono quantizzati in modo aggressivo, spesso fino a 0.</p>
<h3 class="wp-block-heading">Quantizzazione e scelta delle frequenze sicure</h3>
<p>Prima di essere salvati in JPEG, i coefficienti DCT vengono divisi per una matrice di quantizzazione <img loading="lazy" decoding="async" src="https://renor.it/wp-content/ql-cache/quicklatex.com-cd69090f5c2d8ab2c05b77ea4f2526b5_l3.png" class="ql-img-inline-formula quicklatex-auto-format" alt="&#81;&#95;&#123;&#117;&#44;&#118;&#125;" title="Rendered by QuickLaTeX.com" height="18" width="33" style="vertical-align: -6px;"/>, specifica per ogni frequenza:</p>
<div class="renor-latex-display"><p class="ql-center-displayed-equation" style="line-height: 44px;"><span class="ql-right-eqno"> (2) </span><span class="ql-left-eqno"> &nbsp; </span><img loading="lazy" decoding="async" src="https://renor.it/wp-content/ql-cache/quicklatex.com-7ae80d983f177b9a22c1b96106bcb2a9_l3.png" height="44" width="162" class="ql-img-displayed-equation quicklatex-auto-format" alt="&#92;&#98;&#101;&#103;&#105;&#110;&#123;&#100;&#105;&#115;&#112;&#108;&#97;&#121;&#109;&#97;&#116;&#104;&#125; &#92;&#119;&#105;&#100;&#101;&#116;&#105;&#108;&#100;&#101;&#123;&#67;&#125;&#95;&#123;&#117;&#44;&#118;&#125;&#61;&#92;&#111;&#112;&#101;&#114;&#97;&#116;&#111;&#114;&#110;&#97;&#109;&#101;&#123;&#114;&#111;&#117;&#110;&#100;&#125;&#92;&#33;&#92;&#108;&#101;&#102;&#116;&#40;&#92;&#102;&#114;&#97;&#99;&#123;&#67;&#95;&#123;&#117;&#44;&#118;&#125;&#125;&#123;&#81;&#95;&#123;&#117;&#44;&#118;&#125;&#125;&#92;&#114;&#105;&#103;&#104;&#116;&#41; &#92;&#101;&#110;&#100;&#123;&#100;&#105;&#115;&#112;&#108;&#97;&#121;&#109;&#97;&#116;&#104;&#125;" title="Rendered by QuickLaTeX.com"/></p></div>
<p>Più alto è il valore di <img loading="lazy" decoding="async" src="https://renor.it/wp-content/ql-cache/quicklatex.com-cd69090f5c2d8ab2c05b77ea4f2526b5_l3.png" class="ql-img-inline-formula quicklatex-auto-format" alt="&#81;&#95;&#123;&#117;&#44;&#118;&#125;" title="Rendered by QuickLaTeX.com" height="18" width="33" style="vertical-align: -6px;"/>, maggiore sarà la perdita di precisione, con la possibilità che i coefficienti vengano ridotti a zero.<br />Per questo motivo, nel nostro algoritmo operiamo su un sottoinsieme a bassa frequenza dei coefficienti AC, in posizioni dove la quantizzazione è moderata e i valori sopravvivono meglio alla compressione.<br />Evitiamo inoltre i coefficienti troppo bassi (DC incluso), che potrebbero introdurre artefatti visibili se modificati.</p>
<h3 class="wp-block-heading">Codifica di un bit nel coefficiente</h3>
<p>Per garantire la sopravvivenza del bit dopo la compressione JPEG, invece di usare la parità, imponiamo il segno del coefficiente in base al bit da scrivere:</p>
<div class="renor-latex-display"><p class="ql-center-displayed-equation" style="line-height: 54px;"><span class="ql-right-eqno"> (3&#8242;) </span><span class="ql-left-eqno"> &nbsp; </span><img loading="lazy" decoding="async" src="https://renor.it/wp-content/ql-cache/quicklatex.com-a22d16328610d47df40001b4c9d8ad4e_l3.png" height="54" width="337" class="ql-img-displayed-equation quicklatex-auto-format" alt="&#92;&#98;&#101;&#103;&#105;&#110;&#123;&#100;&#105;&#115;&#112;&#108;&#97;&#121;&#109;&#97;&#116;&#104;&#125; &#92;&#111;&#112;&#101;&#114;&#97;&#116;&#111;&#114;&#110;&#97;&#109;&#101;&#123;&#101;&#109;&#98;&#101;&#100;&#125;&#40;&#99;&#44;&#98;&#41;&#61; &#92;&#98;&#101;&#103;&#105;&#110;&#123;&#99;&#97;&#115;&#101;&#115;&#125; &#43;&#92;&#116;&#101;&#120;&#116;&#123;&#109;&#105;&#110;&#65;&#109;&#112;&#125;&#43;&#92;&#116;&#101;&#120;&#116;&#123;&#98;&#111;&#111;&#115;&#116;&#125;&#44;&#32;&#38;&#32;&#98;&#61;&#48;&#44;&#92;&#92; &#45;&#92;&#116;&#101;&#120;&#116;&#123;&#109;&#105;&#110;&#65;&#109;&#112;&#125;&#45;&#92;&#116;&#101;&#120;&#116;&#123;&#98;&#111;&#111;&#115;&#116;&#125;&#44;&#32;&#38;&#32;&#98;&#61;&#49;&#46; &#92;&#101;&#110;&#100;&#123;&#99;&#97;&#115;&#101;&#115;&#125; &#92;&#101;&#110;&#100;&#123;&#100;&#105;&#115;&#112;&#108;&#97;&#121;&#109;&#97;&#116;&#104;&#125;" title="Rendered by QuickLaTeX.com"/></p></div>
<p class="p1">Dove:<br />• <img loading="lazy" decoding="async" src="https://renor.it/wp-content/ql-cache/quicklatex.com-fc1945d79b767f05e0fb239e856a6ba4_l3.png" class="ql-img-inline-formula quicklatex-auto-format" alt="&#92;&#116;&#101;&#120;&#116;&#123;&#109;&#105;&#110;&#65;&#109;&#112;&#125;" title="Rendered by QuickLaTeX.com" height="17" width="68" style="vertical-align: -4px;"/> garantisce un valore sufficientemente lontano da zero (tipicamente ≥ 80),<br />• <img loading="lazy" decoding="async" src="https://renor.it/wp-content/ql-cache/quicklatex.com-adb5446b7c5c59b04b6130e6bf9ee412_l3.png" class="ql-img-inline-formula quicklatex-auto-format" alt="&#92;&#116;&#101;&#120;&#116;&#123;&#98;&#111;&#111;&#115;&#116;&#125;" title="Rendered by QuickLaTeX.com" height="12" width="42" style="vertical-align: 0px;"/> (es. 64) aumenta la distanza dal centro per evitare l’annullamento in fase di quantizzazione.</p>
<p class="p2">In questo modo, anche dopo trasformazioni lossy, il segno resta inalterato e il bit può essere recuperato in lettura.</p>
<p>Se successivamente desideriamo leggere il bit, ci basterà valutare il <strong>segno</strong> del coefficiente DCT quantizzato:</p>
<div class="renor-latex-display"><p class="ql-center-displayed-equation" style="line-height: 54px;"><span class="ql-right-eqno"> (4&#8242;) </span><span class="ql-left-eqno"> &nbsp; </span><img loading="lazy" decoding="async" src="https://renor.it/wp-content/ql-cache/quicklatex.com-c80227bfe940198f582105bbda6ab395_l3.png" height="54" width="147" class="ql-img-displayed-equation quicklatex-auto-format" alt="&#92;&#98;&#101;&#103;&#105;&#110;&#123;&#100;&#105;&#115;&#112;&#108;&#97;&#121;&#109;&#97;&#116;&#104;&#125; &#98;&#61; &#92;&#98;&#101;&#103;&#105;&#110;&#123;&#99;&#97;&#115;&#101;&#115;&#125; &#48;&#44;&#32;&#38;&#32;&#92;&#119;&#105;&#100;&#101;&#116;&#105;&#108;&#100;&#101;&#123;&#67;&#125;&#95;&#123;&#117;&#44;&#118;&#125;&#92;&#103;&#101;&#32;&#48;&#44;&#92;&#92; &#49;&#44;&#32;&#38;&#32;&#92;&#119;&#105;&#100;&#101;&#116;&#105;&#108;&#100;&#101;&#123;&#67;&#125;&#95;&#123;&#117;&#44;&#118;&#125;&#60;&#48;&#46; &#92;&#101;&#110;&#100;&#123;&#99;&#97;&#115;&#101;&#115;&#125; &#92;&#101;&#110;&#100;&#123;&#100;&#105;&#115;&#112;&#108;&#97;&#121;&#109;&#97;&#116;&#104;&#125;" title="Rendered by QuickLaTeX.com"/></p></div>
<p>In altre parole, un coefficiente positivo indica bit 0, uno negativo indica bit 1.</p>
<p>Questo metodo è più robusto, perché il segno di un coefficiente sopravvive a molte trasformazioni lossy, a differenza del singolo bit meno significativo.</p>
<h3 class="wp-block-heading">Ricostruzione (Inverse DCT)</h3>
<p>Dopo aver modificato i coefficienti, invertiamo la trasformazione per ottenere il blocco d&#8217;immagine marcato: </p>
<div class="renor-latex-display"><p class="ql-center-displayed-equation" style="line-height: 52px;"><span class="ql-right-eqno"> (5) </span><span class="ql-left-eqno"> &nbsp; </span><img loading="lazy" decoding="async" src="https://renor.it/wp-content/ql-cache/quicklatex.com-36281b5cbdd0eff9ef61c5b327782eb6_l3.png" height="52" width="504" class="ql-img-displayed-equation quicklatex-auto-format" alt="&#92;&#98;&#101;&#103;&#105;&#110;&#123;&#100;&#105;&#115;&#112;&#108;&#97;&#121;&#109;&#97;&#116;&#104;&#125; &#102;&#95;&#123;&#120;&#44;&#121;&#125;&#61;&#92;&#102;&#114;&#97;&#99;&#123;&#49;&#125;&#123;&#52;&#125; &#92;&#115;&#117;&#109;&#95;&#123;&#117;&#61;&#48;&#125;&#94;&#123;&#55;&#125;&#92;&#115;&#117;&#109;&#95;&#123;&#118;&#61;&#48;&#125;&#94;&#123;&#55;&#125; &#92;&#97;&#108;&#112;&#104;&#97;&#40;&#117;&#41;&#92;&#97;&#108;&#112;&#104;&#97;&#40;&#118;&#41;&#92;&#119;&#105;&#100;&#101;&#116;&#105;&#108;&#100;&#101;&#123;&#67;&#125;&#95;&#123;&#117;&#44;&#118;&#125; &#92;&#99;&#111;&#115;&#92;&#33;&#92;&#108;&#101;&#102;&#116;&#40;&#92;&#102;&#114;&#97;&#99;&#123;&#40;&#50;&#120;&#43;&#49;&#41;&#117;&#92;&#112;&#105;&#125;&#123;&#49;&#54;&#125;&#92;&#114;&#105;&#103;&#104;&#116;&#41; &#92;&#99;&#111;&#115;&#92;&#33;&#92;&#108;&#101;&#102;&#116;&#40;&#92;&#102;&#114;&#97;&#99;&#123;&#40;&#50;&#121;&#43;&#49;&#41;&#118;&#92;&#112;&#105;&#125;&#123;&#49;&#54;&#125;&#92;&#114;&#105;&#103;&#104;&#116;&#41; &#92;&#101;&#110;&#100;&#123;&#100;&#105;&#115;&#112;&#108;&#97;&#121;&#109;&#97;&#116;&#104;&#125;" title="Rendered by QuickLaTeX.com"/></p></div>
<p>L’errore massimo introdotto da una variazione di ±1 su un coefficiente di media frequenza è inferiore a 1 quantum in luminanza, sotto la soglia di percezione umano-visiva per fotografie reali.</p>
<h3 class="wp-block-heading">Ridondanza ciclica per indurre robustezza</h3>
<p>Per fronteggiare compressioni o ritagli, codifichiamo il messaggio M duplicando ciascun bit k volte e applicando un voto di maggioranza in lettura. Con k=3:</p>
<div class="renor-latex-display"><p class="ql-center-displayed-equation" style="line-height: 14px;"><span class="ql-right-eqno"> (6) </span><span class="ql-left-eqno"> &nbsp; </span><img loading="lazy" decoding="async" src="https://renor.it/wp-content/ql-cache/quicklatex.com-27afe9d7449c5251157b2f153a81e164_l3.png" height="14" width="335" class="ql-img-displayed-equation quicklatex-auto-format" alt="&#92;&#98;&#101;&#103;&#105;&#110;&#123;&#100;&#105;&#115;&#112;&#108;&#97;&#121;&#109;&#97;&#116;&#104;&#125; &#77;&#61;&#98;&#95;&#49;&#98;&#95;&#50;&#92;&#100;&#111;&#116;&#115;&#32;&#98;&#95;&#110; &#92;&#59;&#92;&#108;&#111;&#110;&#103;&#114;&#105;&#103;&#104;&#116;&#97;&#114;&#114;&#111;&#119;&#92;&#59; &#98;&#95;&#49;&#98;&#95;&#49;&#98;&#95;&#49;&#92;&#44;&#98;&#95;&#50;&#98;&#95;&#50;&#98;&#95;&#50;&#92;&#100;&#111;&#116;&#115;&#32;&#98;&#95;&#110;&#98;&#95;&#110;&#98;&#95;&#110; &#92;&#101;&#110;&#100;&#123;&#100;&#105;&#115;&#112;&#108;&#97;&#121;&#109;&#97;&#116;&#104;&#125;" title="Rendered by QuickLaTeX.com"/></p></div>
<p>Il recupero corretto è garantito finché <strong>almeno due copie su tre sopravvivono</strong>.</p>
<h2 class="wp-block-heading">Dalle formule al codice: la classe DCT</h2>
<p>Ora che abbiamo formalizzato l’intero impianto matematico, possiamo tradurre l’equazione (1) e la sua inversa direttamente in PHP.</p>
<p>Per mantenere il progetto in puro PHP, senza estensioni native né dipendenze esterne, implementiamo la DCT manualmente su blocchi 8×8.</p>
<p>Questo approccio è sufficientemente veloce per immagini fino a qualche megapixel e, soprattutto, è trasparente e facile da comprendere e modificare.</p>
<p>Il progetto è organizzato con Composer e autoload PSR-4, ma la classe Dct è <strong>completamente autonoma</strong> e <strong>non richiede librerie esterne</strong>.</p>
<p>Se in futuro vorrai estendere il sistema con analisi matriciali (es. box counting o misure di distorsione), potrai integrare MathPHP, ma non è necessaria per la DCT.</p>
<h3 class="wp-block-heading">composer.json</h3>


<div class="wp-block-kevinbatdorf-code-block-pro" style="font-size: .875rem;font-family: Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height: 1.25rem;--cbp-tab-width: 2" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono">
<pre class="shiki nord" style="background-color: #2e3440ff"><code><span class="line"><span style="color: #eceff4">{</span></span>
<span class="line">    <span style="color: #eceff4">"</span><span style="color: #8fbcbb">name</span><span style="color: #eceff4">"</span><span style="color: #eceff4">:</span> <span style="color: #eceff4">"</span><span style="color: #a3be8c">renornad/php-dct-invisible-watermark</span><span style="color: #eceff4">"</span><span style="color: #eceff4">,</span></span>
<span class="line">    <span style="color: #eceff4">"</span><span style="color: #8fbcbb">description</span><span style="color: #eceff4">"</span><span style="color: #eceff4">:</span> <span style="color: #eceff4">"</span><span style="color: #a3be8c">Pure-PHP DCT watermarking library for JPEG images.</span><span style="color: #eceff4">"</span><span style="color: #eceff4">,</span></span>
<span class="line">    <span style="color: #eceff4">"</span><span style="color: #8fbcbb">type</span><span style="color: #eceff4">"</span><span style="color: #eceff4">:</span> <span style="color: #eceff4">"</span><span style="color: #a3be8c">project</span><span style="color: #eceff4">"</span><span style="color: #eceff4">,</span></span>
<span class="line">    <span style="color: #eceff4">"</span><span style="color: #8fbcbb">license</span><span style="color: #eceff4">"</span><span style="color: #eceff4">:</span> <span style="color: #eceff4">"</span><span style="color: #a3be8c">MIT</span><span style="color: #eceff4">"</span><span style="color: #eceff4">,</span></span>
<span class="line">    <span style="color: #eceff4">"</span><span style="color: #8fbcbb">require</span><span style="color: #eceff4">"</span><span style="color: #eceff4">:</span> <span style="color: #eceff4">{</span></span>
<span class="line">      <span style="color: #eceff4">"</span><span style="color: #8fbcbb">php</span><span style="color: #eceff4">"</span><span style="color: #eceff4">:</span> <span style="color: #eceff4">"</span><span style="color: #a3be8c">&gt;=8.3</span><span style="color: #eceff4">"</span></span>
<span class="line">    <span style="color: #eceff4">},</span></span>
<span class="line">    <span style="color: #eceff4">"</span><span style="color: #8fbcbb">autoload</span><span style="color: #eceff4">"</span><span style="color: #eceff4">:</span> <span style="color: #eceff4">{</span></span>
<span class="line">      <span style="color: #eceff4">"</span><span style="color: #8fbcbb">psr-4</span><span style="color: #eceff4">"</span><span style="color: #eceff4">:</span> <span style="color: #eceff4">{</span></span>
<span class="line">        <span style="color: #eceff4">"</span><span style="color: #8fbcbb">Renor</span><span style="color: #ebcb8b"></span><span style="color: #8fbcbb">Watermark</span><span style="color: #ebcb8b"></span><span style="color: #eceff4">"</span><span style="color: #eceff4">:</span> <span style="color: #eceff4">"</span><span style="color: #a3be8c">src/</span><span style="color: #eceff4">"</span></span>
<span class="line">      <span style="color: #eceff4">}</span></span>
<span class="line">    <span style="color: #eceff4">}</span></span>
<span class="line">  <span style="color: #eceff4">}</span></span></code></pre>
</div>


<p>Dopo aver definito il nostro file composer.json procediamo all&#8217;installazione. Andiamo su terminale e digitiamo il comando:</p>


<pre class="wp-block-code"><code>composer install</code></pre>


<p>A questo punto composer creerà il file composer.lock e la cartella vendor che però non installerà pacchetti da Packagist perché non stiamo includendo dipendenze.</p>
<h2 class="wp-block-heading">src/Dct.php</h2>
<p>Ora possiamo finalmente scrivere la classe Dct. Ricordo che è preferibile inserire i commenti al codice, come standard in inglese:</p>


<div class="wp-block-kevinbatdorf-code-block-pro" style="font-size: .875rem;font-family: Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height: 1.25rem;--cbp-tab-width: 2" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono">
<pre class="shiki dark-plus" style="background-color: #1e1e1e"><code><span class="line"><span style="color: #d4d4d4">&lt;?php</span></span>

<span class="line"><span style="color: #c586c0">declare</span><span style="color: #d4d4d4">(strict_types=</span><span style="color: #b5cea8">1</span><span style="color: #d4d4d4">);</span></span>

<span class="line"><span style="color: #569cd6">namespace</span> <span style="color: #4ec9b0">RenorWatermark</span><span style="color: #d4d4d4">;</span></span>

<span class="line"><span style="color: #6a9955">/**</span></span>
<span class="line"><span style="color: #6a9955"> * 2-D Discrete Cosine Transform (DCT) and its inverse (IDCT) for 8x8 blocks.</span></span>
<span class="line"><span style="color: #6a9955"> */</span></span>
<span class="line"><span style="color: #569cd6">final</span> <span style="color: #569cd6">class</span> <span style="color: #4ec9b0">Dct</span></span>
<span class="line"><span style="color: #d4d4d4">{</span></span>
<span class="line">    <span style="color: #569cd6">private</span> <span style="color: #569cd6">const</span><span style="color: #d4d4d4"> N = </span><span style="color: #b5cea8">8</span><span style="color: #d4d4d4">;</span></span>
<span class="line">    <span style="color: #569cd6">private</span> <span style="color: #569cd6">const</span><span style="color: #d4d4d4"> SQRT_2_INV = </span><span style="color: #b5cea8">0.7071067811865476</span><span style="color: #d4d4d4">; </span><span style="color: #6a9955">// 1 / sqrt(2)</span></span>

<span class="line">    <span style="color: #6a9955">/**</span></span>
<span class="line"><span style="color: #6a9955">     * Performs the forward DCT on an 8x8 block of pixel intensities (0-255).</span></span>
<span class="line"><span style="color: #6a9955">     */</span></span>
<span class="line">    <span style="color: #569cd6">public</span> <span style="color: #569cd6">static</span> <span style="color: #569cd6">function</span> <span style="color: #dcdcaa">forward</span><span style="color: #d4d4d4">(</span><span style="color: #569cd6">array</span> <span style="color: #9cdcfe">$block</span><span style="color: #d4d4d4">): </span><span style="color: #569cd6">array</span></span>
<span class="line"><span style="color: #d4d4d4">    {</span></span>
<span class="line">        <span style="color: #569cd6">self</span><span style="color: #d4d4d4">::</span><span style="color: #dcdcaa">assertBlock</span><span style="color: #d4d4d4">(</span><span style="color: #9cdcfe">$block</span><span style="color: #d4d4d4">);</span></span>
<span class="line">        <span style="color: #9cdcfe">$C</span><span style="color: #d4d4d4"> = [];</span></span>

<span class="line">        <span style="color: #c586c0">for</span><span style="color: #d4d4d4"> (</span><span style="color: #9cdcfe">$u</span><span style="color: #d4d4d4"> = </span><span style="color: #b5cea8">0</span><span style="color: #d4d4d4">; </span><span style="color: #9cdcfe">$u</span><span style="color: #d4d4d4"> &lt; </span><span style="color: #569cd6">self</span><span style="color: #d4d4d4">::N; ++</span><span style="color: #9cdcfe">$u</span><span style="color: #d4d4d4">) {</span></span>
<span class="line">            <span style="color: #9cdcfe">$alphaU</span><span style="color: #d4d4d4"> = (</span><span style="color: #9cdcfe">$u</span><span style="color: #d4d4d4"> === </span><span style="color: #b5cea8">0</span><span style="color: #d4d4d4">) ? </span><span style="color: #569cd6">self</span><span style="color: #d4d4d4">::SQRT_2_INV : </span><span style="color: #b5cea8">1.0</span><span style="color: #d4d4d4">;</span></span>
<span class="line">            <span style="color: #c586c0">for</span><span style="color: #d4d4d4"> (</span><span style="color: #9cdcfe">$v</span><span style="color: #d4d4d4"> = </span><span style="color: #b5cea8">0</span><span style="color: #d4d4d4">; </span><span style="color: #9cdcfe">$v</span><span style="color: #d4d4d4"> &lt; </span><span style="color: #569cd6">self</span><span style="color: #d4d4d4">::N; ++</span><span style="color: #9cdcfe">$v</span><span style="color: #d4d4d4">) {</span></span>
<span class="line">                <span style="color: #9cdcfe">$alphaV</span><span style="color: #d4d4d4"> = (</span><span style="color: #9cdcfe">$v</span><span style="color: #d4d4d4"> === </span><span style="color: #b5cea8">0</span><span style="color: #d4d4d4">) ? </span><span style="color: #569cd6">self</span><span style="color: #d4d4d4">::SQRT_2_INV : </span><span style="color: #b5cea8">1.0</span><span style="color: #d4d4d4">;</span></span>
<span class="line">                <span style="color: #9cdcfe">$sum</span><span style="color: #d4d4d4"> = </span><span style="color: #b5cea8">0.0</span><span style="color: #d4d4d4">;</span></span>
<span class="line">                <span style="color: #c586c0">for</span><span style="color: #d4d4d4"> (</span><span style="color: #9cdcfe">$x</span><span style="color: #d4d4d4"> = </span><span style="color: #b5cea8">0</span><span style="color: #d4d4d4">; </span><span style="color: #9cdcfe">$x</span><span style="color: #d4d4d4"> &lt; </span><span style="color: #569cd6">self</span><span style="color: #d4d4d4">::N; ++</span><span style="color: #9cdcfe">$x</span><span style="color: #d4d4d4">) {</span></span>
<span class="line">                    <span style="color: #c586c0">for</span><span style="color: #d4d4d4"> (</span><span style="color: #9cdcfe">$y</span><span style="color: #d4d4d4"> = </span><span style="color: #b5cea8">0</span><span style="color: #d4d4d4">; </span><span style="color: #9cdcfe">$y</span><span style="color: #d4d4d4"> &lt; </span><span style="color: #569cd6">self</span><span style="color: #d4d4d4">::N; ++</span><span style="color: #9cdcfe">$y</span><span style="color: #d4d4d4">) {</span></span>
<span class="line">                        <span style="color: #9cdcfe">$cosX</span><span style="color: #d4d4d4"> = </span><span style="color: #dcdcaa">cos</span><span style="color: #d4d4d4">((</span><span style="color: #b5cea8">2</span><span style="color: #d4d4d4"> * </span><span style="color: #9cdcfe">$x</span><span style="color: #d4d4d4"> + </span><span style="color: #b5cea8">1</span><span style="color: #d4d4d4">) * </span><span style="color: #9cdcfe">$u</span><span style="color: #d4d4d4"> * M_PI / (</span><span style="color: #b5cea8">2</span><span style="color: #d4d4d4"> * </span><span style="color: #569cd6">self</span><span style="color: #d4d4d4">::N));</span></span>
<span class="line">                        <span style="color: #9cdcfe">$cosY</span><span style="color: #d4d4d4"> = </span><span style="color: #dcdcaa">cos</span><span style="color: #d4d4d4">((</span><span style="color: #b5cea8">2</span><span style="color: #d4d4d4"> * </span><span style="color: #9cdcfe">$y</span><span style="color: #d4d4d4"> + </span><span style="color: #b5cea8">1</span><span style="color: #d4d4d4">) * </span><span style="color: #9cdcfe">$v</span><span style="color: #d4d4d4"> * M_PI / (</span><span style="color: #b5cea8">2</span><span style="color: #d4d4d4"> * </span><span style="color: #569cd6">self</span><span style="color: #d4d4d4">::N));</span></span>
<span class="line">                        <span style="color: #9cdcfe">$sum</span><span style="color: #d4d4d4"> += </span><span style="color: #9cdcfe">$block</span><span style="color: #d4d4d4">[</span><span style="color: #9cdcfe">$x</span><span style="color: #d4d4d4">][</span><span style="color: #9cdcfe">$y</span><span style="color: #d4d4d4">] * </span><span style="color: #9cdcfe">$cosX</span><span style="color: #d4d4d4"> * </span><span style="color: #9cdcfe">$cosY</span><span style="color: #d4d4d4">;</span></span>
<span class="line"><span style="color: #d4d4d4">                    }</span></span>
<span class="line"><span style="color: #d4d4d4">                }</span></span>
<span class="line">                <span style="color: #6a9955">// The DCT formula includes a factor of 1/4</span></span>
<span class="line">                <span style="color: #9cdcfe">$C</span><span style="color: #d4d4d4">[</span><span style="color: #9cdcfe">$u</span><span style="color: #d4d4d4">][</span><span style="color: #9cdcfe">$v</span><span style="color: #d4d4d4">] = </span><span style="color: #b5cea8">0.25</span><span style="color: #d4d4d4"> * </span><span style="color: #9cdcfe">$alphaU</span><span style="color: #d4d4d4"> * </span><span style="color: #9cdcfe">$alphaV</span><span style="color: #d4d4d4"> * </span><span style="color: #9cdcfe">$sum</span><span style="color: #d4d4d4">;</span></span>
<span class="line"><span style="color: #d4d4d4">            }</span></span>
<span class="line"><span style="color: #d4d4d4">        }</span></span>
<span class="line">        <span style="color: #c586c0">return</span> <span style="color: #9cdcfe">$C</span><span style="color: #d4d4d4">;</span></span>
<span class="line"><span style="color: #d4d4d4">    }</span></span>

<span class="line">    <span style="color: #6a9955">/**</span></span>
<span class="line"><span style="color: #6a9955">     * Performs the inverse DCT on an 8x8 block of coefficients, </span></span>
<span class="line"><span style="color: #6a9955">     * returning pixel values in the range [0..255].</span></span>
<span class="line"><span style="color: #6a9955">     */</span></span>
<span class="line">    <span style="color: #569cd6">public</span> <span style="color: #569cd6">static</span> <span style="color: #569cd6">function</span> <span style="color: #dcdcaa">inverse</span><span style="color: #d4d4d4">(</span><span style="color: #569cd6">array</span> <span style="color: #9cdcfe">$coeff</span><span style="color: #d4d4d4">): </span><span style="color: #569cd6">array</span></span>
<span class="line"><span style="color: #d4d4d4">    {</span></span>
<span class="line">        <span style="color: #569cd6">self</span><span style="color: #d4d4d4">::</span><span style="color: #dcdcaa">assertBlock</span><span style="color: #d4d4d4">(</span><span style="color: #9cdcfe">$coeff</span><span style="color: #d4d4d4">);</span></span>
<span class="line">        <span style="color: #9cdcfe">$f</span><span style="color: #d4d4d4"> = [];</span></span>

<span class="line">        <span style="color: #c586c0">for</span><span style="color: #d4d4d4"> (</span><span style="color: #9cdcfe">$x</span><span style="color: #d4d4d4"> = </span><span style="color: #b5cea8">0</span><span style="color: #d4d4d4">; </span><span style="color: #9cdcfe">$x</span><span style="color: #d4d4d4"> &lt; </span><span style="color: #569cd6">self</span><span style="color: #d4d4d4">::N; ++</span><span style="color: #9cdcfe">$x</span><span style="color: #d4d4d4">) {</span></span>
<span class="line">            <span style="color: #c586c0">for</span><span style="color: #d4d4d4"> (</span><span style="color: #9cdcfe">$y</span><span style="color: #d4d4d4"> = </span><span style="color: #b5cea8">0</span><span style="color: #d4d4d4">; </span><span style="color: #9cdcfe">$y</span><span style="color: #d4d4d4"> &lt; </span><span style="color: #569cd6">self</span><span style="color: #d4d4d4">::N; ++</span><span style="color: #9cdcfe">$y</span><span style="color: #d4d4d4">) {</span></span>
<span class="line">                <span style="color: #9cdcfe">$sum</span><span style="color: #d4d4d4"> = </span><span style="color: #b5cea8">0.0</span><span style="color: #d4d4d4">;</span></span>
<span class="line">                <span style="color: #c586c0">for</span><span style="color: #d4d4d4"> (</span><span style="color: #9cdcfe">$u</span><span style="color: #d4d4d4"> = </span><span style="color: #b5cea8">0</span><span style="color: #d4d4d4">; </span><span style="color: #9cdcfe">$u</span><span style="color: #d4d4d4"> &lt; </span><span style="color: #569cd6">self</span><span style="color: #d4d4d4">::N; ++</span><span style="color: #9cdcfe">$u</span><span style="color: #d4d4d4">) {</span></span>
<span class="line">                    <span style="color: #9cdcfe">$alphaU</span><span style="color: #d4d4d4"> = (</span><span style="color: #9cdcfe">$u</span><span style="color: #d4d4d4"> === </span><span style="color: #b5cea8">0</span><span style="color: #d4d4d4">) ? </span><span style="color: #569cd6">self</span><span style="color: #d4d4d4">::SQRT_2_INV : </span><span style="color: #b5cea8">1.0</span><span style="color: #d4d4d4">;</span></span>
<span class="line">                    <span style="color: #c586c0">for</span><span style="color: #d4d4d4"> (</span><span style="color: #9cdcfe">$v</span><span style="color: #d4d4d4"> = </span><span style="color: #b5cea8">0</span><span style="color: #d4d4d4">; </span><span style="color: #9cdcfe">$v</span><span style="color: #d4d4d4"> &lt; </span><span style="color: #569cd6">self</span><span style="color: #d4d4d4">::N; ++</span><span style="color: #9cdcfe">$v</span><span style="color: #d4d4d4">) {</span></span>
<span class="line">                        <span style="color: #9cdcfe">$alphaV</span><span style="color: #d4d4d4"> = (</span><span style="color: #9cdcfe">$v</span><span style="color: #d4d4d4"> === </span><span style="color: #b5cea8">0</span><span style="color: #d4d4d4">) ? </span><span style="color: #569cd6">self</span><span style="color: #d4d4d4">::SQRT_2_INV : </span><span style="color: #b5cea8">1.0</span><span style="color: #d4d4d4">;</span></span>
<span class="line">                        <span style="color: #9cdcfe">$cosX</span><span style="color: #d4d4d4"> = </span><span style="color: #dcdcaa">cos</span><span style="color: #d4d4d4">((</span><span style="color: #b5cea8">2</span><span style="color: #d4d4d4"> * </span><span style="color: #9cdcfe">$x</span><span style="color: #d4d4d4"> + </span><span style="color: #b5cea8">1</span><span style="color: #d4d4d4">) * </span><span style="color: #9cdcfe">$u</span><span style="color: #d4d4d4"> * M_PI / (</span><span style="color: #b5cea8">2</span><span style="color: #d4d4d4"> * </span><span style="color: #569cd6">self</span><span style="color: #d4d4d4">::N));</span></span>
<span class="line">                        <span style="color: #9cdcfe">$cosY</span><span style="color: #d4d4d4"> = </span><span style="color: #dcdcaa">cos</span><span style="color: #d4d4d4">((</span><span style="color: #b5cea8">2</span><span style="color: #d4d4d4"> * </span><span style="color: #9cdcfe">$y</span><span style="color: #d4d4d4"> + </span><span style="color: #b5cea8">1</span><span style="color: #d4d4d4">) * </span><span style="color: #9cdcfe">$v</span><span style="color: #d4d4d4"> * M_PI / (</span><span style="color: #b5cea8">2</span><span style="color: #d4d4d4"> * </span><span style="color: #569cd6">self</span><span style="color: #d4d4d4">::N));</span></span>
<span class="line">                        <span style="color: #9cdcfe">$sum</span><span style="color: #d4d4d4"> += </span><span style="color: #9cdcfe">$alphaU</span><span style="color: #d4d4d4"> * </span><span style="color: #9cdcfe">$alphaV</span><span style="color: #d4d4d4"> * </span><span style="color: #9cdcfe">$coeff</span><span style="color: #d4d4d4">[</span><span style="color: #9cdcfe">$u</span><span style="color: #d4d4d4">][</span><span style="color: #9cdcfe">$v</span><span style="color: #d4d4d4">] * </span><span style="color: #9cdcfe">$cosX</span><span style="color: #d4d4d4"> * </span><span style="color: #9cdcfe">$cosY</span><span style="color: #d4d4d4">;</span></span>
<span class="line"><span style="color: #d4d4d4">                    }</span></span>
<span class="line"><span style="color: #d4d4d4">                }</span></span>
<span class="line">                <span style="color: #9cdcfe">$pixel</span><span style="color: #d4d4d4"> = (</span><span style="color: #569cd6">int</span><span style="color: #d4d4d4">) </span><span style="color: #dcdcaa">round</span><span style="color: #d4d4d4">(</span><span style="color: #b5cea8">0.25</span><span style="color: #d4d4d4"> * </span><span style="color: #9cdcfe">$sum</span><span style="color: #d4d4d4">);</span></span>
<span class="line">                <span style="color: #9cdcfe">$f</span><span style="color: #d4d4d4">[</span><span style="color: #9cdcfe">$x</span><span style="color: #d4d4d4">][</span><span style="color: #9cdcfe">$y</span><span style="color: #d4d4d4">] = </span><span style="color: #dcdcaa">max</span><span style="color: #d4d4d4">(</span><span style="color: #b5cea8">0</span><span style="color: #d4d4d4">, </span><span style="color: #dcdcaa">min</span><span style="color: #d4d4d4">(</span><span style="color: #b5cea8">255</span><span style="color: #d4d4d4">, </span><span style="color: #9cdcfe">$pixel</span><span style="color: #d4d4d4">));</span></span>
<span class="line"><span style="color: #d4d4d4">            }</span></span>
<span class="line"><span style="color: #d4d4d4">        }</span></span>
<span class="line">        <span style="color: #c586c0">return</span> <span style="color: #9cdcfe">$f</span><span style="color: #d4d4d4">;</span></span>
<span class="line"><span style="color: #d4d4d4">    }</span></span>

<span class="line">    <span style="color: #6a9955">/**</span></span>
<span class="line"><span style="color: #6a9955">     * Checks that the array is exactly 8x8.</span></span>
<span class="line"><span style="color: #6a9955">     */</span></span>
<span class="line">    <span style="color: #569cd6">private</span> <span style="color: #569cd6">static</span> <span style="color: #569cd6">function</span> <span style="color: #dcdcaa">assertBlock</span><span style="color: #d4d4d4">(</span><span style="color: #569cd6">array</span> <span style="color: #9cdcfe">$block</span><span style="color: #d4d4d4">): </span><span style="color: #569cd6">void</span></span>
<span class="line"><span style="color: #d4d4d4">    {</span></span>
<span class="line">        <span style="color: #c586c0">if</span><span style="color: #d4d4d4"> (</span><span style="color: #dcdcaa">count</span><span style="color: #d4d4d4">(</span><span style="color: #9cdcfe">$block</span><span style="color: #d4d4d4">) !== </span><span style="color: #569cd6">self</span><span style="color: #d4d4d4">::N) {</span></span>
<span class="line">            <span style="color: #c586c0">throw</span> <span style="color: #569cd6">new</span> <span style="color: #4ec9b0">InvalidArgumentException</span><span style="color: #d4d4d4">(</span><span style="color: #ce9178">'Block must have 8 rows.'</span><span style="color: #d4d4d4">);</span></span>
<span class="line"><span style="color: #d4d4d4">        }</span></span>
<span class="line">        <span style="color: #c586c0">foreach</span><span style="color: #d4d4d4"> (</span><span style="color: #9cdcfe">$block</span><span style="color: #d4d4d4"> as </span><span style="color: #9cdcfe">$row</span><span style="color: #d4d4d4">) {</span></span>
<span class="line">            <span style="color: #c586c0">if</span><span style="color: #d4d4d4"> (</span><span style="color: #dcdcaa">count</span><span style="color: #d4d4d4">(</span><span style="color: #9cdcfe">$row</span><span style="color: #d4d4d4">) !== </span><span style="color: #569cd6">self</span><span style="color: #d4d4d4">::N) {</span></span>
<span class="line">                <span style="color: #c586c0">throw</span> <span style="color: #569cd6">new</span> <span style="color: #4ec9b0">InvalidArgumentException</span><span style="color: #d4d4d4">(</span><span style="color: #ce9178">'Each row must have 8 columns.'</span><span style="color: #d4d4d4">);</span></span>
<span class="line"><span style="color: #d4d4d4">            }</span></span>
<span class="line"><span style="color: #d4d4d4">        }</span></span>
<span class="line"><span style="color: #d4d4d4">    }</span></span>

<span class="line">    <span style="color: #6a9955">/**</span></span>
<span class="line"><span style="color: #6a9955">     * Disallow instantiation.</span></span>
<span class="line"><span style="color: #6a9955">     */</span></span>
<span class="line">    <span style="color: #569cd6">private</span> <span style="color: #569cd6">function</span> <span style="color: #dcdcaa">__construct</span><span style="color: #d4d4d4">()</span></span>
<span class="line"><span style="color: #d4d4d4">    {</span></span>
<span class="line"><span style="color: #d4d4d4">    }</span></span>
<span class="line"><span style="color: #d4d4d4">}</span></span></code></pre>
</div>


<p>Questa classe è il cuore del progetto. Racchiude l’algoritmo della Trasformata Coseno Discreta bidimensionale applicata a blocchi 8×8 pixel, lo stesso schema impiegato dallo standard JPEG. All’avvio del metodo forward, la classe controlla che l’array ricevuto contenga esattamente otto righe e otto colonne; in caso contrario, lancia un’eccezione per evitare che un errore di dimensionamento si propaghi silenziosamente.</p>
<p>Una volta verificata la forma, per ogni coppia di indici di frequenza <img loading="lazy" decoding="async" src="https://renor.it/wp-content/ql-cache/quicklatex.com-9d46ecf43e79cdd15c096896b5052865_l3.png" class="ql-img-inline-formula quicklatex-auto-format" alt="&#117;&#44;&#118;" title="Rendered by QuickLaTeX.com" height="12" width="27" style="vertical-align: -4px;"/>, calcola la doppia somma definita dalla formula canonica della DCT: prende ciascun valore di luminosità <img loading="lazy" decoding="async" src="https://renor.it/wp-content/ql-cache/quicklatex.com-533196a0d71c414a47d0753600045b35_l3.png" class="ql-img-inline-formula quicklatex-auto-format" alt="&#102;&#95;&#123;&#120;&#44;&#121;&#125;" title="Rendered by QuickLaTeX.com" height="18" width="28" style="vertical-align: -6px;"/>, lo moltiplica per due coseni — uno in funzione di <img loading="lazy" decoding="async" src="https://renor.it/wp-content/ql-cache/quicklatex.com-43fe27dc3e528266a619764d90fce60b_l3.png" class="ql-img-inline-formula quicklatex-auto-format" alt="&#117;" title="Rendered by QuickLaTeX.com" height="8" width="10" style="vertical-align: 0px;"/> e della coordinata <img loading="lazy" decoding="async" src="https://renor.it/wp-content/ql-cache/quicklatex.com-ede05c264bba0eda080918aaa09c4658_l3.png" class="ql-img-inline-formula quicklatex-auto-format" alt="&#120;" title="Rendered by QuickLaTeX.com" height="8" width="10" style="vertical-align: 0px;"/>, l’altro in funzione di <img loading="lazy" decoding="async" src="https://renor.it/wp-content/ql-cache/quicklatex.com-ef71511c70f0e4b25cc6bd69f3bc20c2_l3.png" class="ql-img-inline-formula quicklatex-auto-format" alt="&#118;" title="Rendered by QuickLaTeX.com" height="8" width="9" style="vertical-align: 0px;"/> e della coordinata <img loading="lazy" decoding="async" src="https://renor.it/wp-content/ql-cache/quicklatex.com-0af556714940c351c933bba8cf840796_l3.png" class="ql-img-inline-formula quicklatex-auto-format" alt="&#121;" title="Rendered by QuickLaTeX.com" height="12" width="9" style="vertical-align: -4px;"/> — e accumula il risultato. Terminata la scansione del blocco, applica il fattore di normalizzazione <img loading="lazy" decoding="async" src="https://renor.it/wp-content/ql-cache/quicklatex.com-7b3f78381f480bd585cbee00d85eba72_l3.png" class="ql-img-inline-formula quicklatex-auto-format" alt="&#92;&#116;&#102;&#114;&#97;&#99;&#123;&#49;&#125;&#123;&#52;&#125;&#92;&#97;&#108;&#112;&#104;&#97;&#40;&#117;&#41;&#92;&#97;&#108;&#112;&#104;&#97;&#40;&#118;&#41;" title="Rendered by QuickLaTeX.com" height="22" width="78" style="vertical-align: -6px;"/>, dove <img loading="lazy" decoding="async" src="https://renor.it/wp-content/ql-cache/quicklatex.com-bb42b8140b08d291eab286b7efc5a432_l3.png" class="ql-img-inline-formula quicklatex-auto-format" alt="&#92;&#97;&#108;&#112;&#104;&#97;&#40;&#48;&#41;&#61;&#92;&#102;&#114;&#97;&#99;&#123;&#49;&#125;&#123;&#92;&#115;&#113;&#114;&#116;&#123;&#50;&#125;&#125;" title="Rendered by QuickLaTeX.com" height="27" width="79" style="vertical-align: -11px;"/> e <img loading="lazy" decoding="async" src="https://renor.it/wp-content/ql-cache/quicklatex.com-7c626d594bf03530ab2b4e16fda1a84a_l3.png" class="ql-img-inline-formula quicklatex-auto-format" alt="&#92;&#97;&#108;&#112;&#104;&#97;&#40;&#107;&#41;&#61;&#49;" title="Rendered by QuickLaTeX.com" height="19" width="67" style="vertical-align: -5px;"/> per <img loading="lazy" decoding="async" src="https://renor.it/wp-content/ql-cache/quicklatex.com-2ed118e986086a564c50a9a125c25bb4_l3.png" class="ql-img-inline-formula quicklatex-auto-format" alt="&#107;&#92;&#103;&#101;&#32;&#49;" title="Rendered by QuickLaTeX.com" height="15" width="41" style="vertical-align: -3px;"/>, così che il coefficiente <img loading="lazy" decoding="async" src="https://renor.it/wp-content/ql-cache/quicklatex.com-d28eb1caf4d0c1c6fad49a76dcf1fcd7_l3.png" class="ql-img-inline-formula quicklatex-auto-format" alt="&#67;&#95;&#123;&#48;&#44;&#48;&#125;" title="Rendered by QuickLaTeX.com" height="18" width="31" style="vertical-align: -6px;"/> conservi la media luminosa e tutti gli altri rappresentino, con la corretta scala, le componenti di dettaglio via via più fini. Il metodo restituisce quindi una matrice 8×8 di coefficienti in virgola mobile: è su questa rappresentazione in frequenza che più avanti incideremo i bit del watermark.</p>
<p>Il percorso inverso è affidato al metodo inverse. Anche qui, prima di qualsiasi elaborazione, la classe impone la verifica della forma del blocco. Per ogni coppia di coordinate di pixel <img loading="lazy" decoding="async" src="https://renor.it/wp-content/ql-cache/quicklatex.com-adc5a68ffaee1d41b37612d9733b4496_l3.png" class="ql-img-inline-formula quicklatex-auto-format" alt="&#120;&#44;&#121;" title="Rendered by QuickLaTeX.com" height="12" width="27" style="vertical-align: -4px;"/>, ricostruisce la luminanza sommando le 64 frequenze, ciascuna ponderata dal prodotto dei coseni e dai fattori di normalizzazione <img loading="lazy" decoding="async" src="https://renor.it/wp-content/ql-cache/quicklatex.com-7e8439594a36787d99d464e65263b0d6_l3.png" class="ql-img-inline-formula quicklatex-auto-format" alt="&#92;&#97;&#108;&#112;&#104;&#97;&#40;&#117;&#41;&#92;&#97;&#108;&#112;&#104;&#97;&#40;&#118;&#41;" title="Rendered by QuickLaTeX.com" height="19" width="69" style="vertical-align: -5px;"/>. Il valore finale viene moltiplicato per <img loading="lazy" decoding="async" src="https://renor.it/wp-content/ql-cache/quicklatex.com-bc0cbfb7e7a2c46054a9130a25f73d75_l3.png" class="ql-img-inline-formula quicklatex-auto-format" alt="&#92;&#116;&#102;&#114;&#97;&#99;&#123;&#49;&#125;&#123;&#52;&#125;" title="Rendered by QuickLaTeX.com" height="22" width="7" style="vertical-align: -6px;"/>, arrotondato all’intero più vicino e limitato all’intervallo 0–255, così da evitare che eventuali errori numerici facciano uscire il risultato dallo spazio colore.</p>
<p>L’implementazione segue fedelmente la definizione matematica, senza ricorrere ad accelerazioni FFT o SIMD, privilegiando la chiarezza didattica rispetto alle prestazioni. Il costruttore è privato, la classe non può essere istanziata, e tutti i metodi sono statici e privi di stato interno: in questo modo la DCT si comporta come una funzione pura, facilmente testabile e riutilizzabile. Quando, nei prossimi paragrafi, la useremo per incastonare un bit modificando il segno di un coefficiente a bassa frequenza, potremo essere certi che la trasformazione diretta e inversa siano numericamente coerenti e che l’alterazione resti confinata ai valori che intendiamo manipolare.</p>
<h2 class="wp-block-heading">src/Watermarker.php</h2>
<p>La classe Watermarker è la regista che orchestra la fase più delicata dell’intero progetto. Riceve in ingresso o in uscita una sequenza di blocchi 8×8 di coefficienti DCT già calcolati dalla classe Dct e, senza occuparsi della lettura fisica del file JPEG, si limita a manipolare quei numeri per nascondere o recuperare un testo ASCII.</p>


<div class="wp-block-kevinbatdorf-code-block-pro" style="font-size: .875rem;font-family: Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height: 1.25rem;--cbp-tab-width: 2" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono">
<pre class="shiki dark-plus" style="background-color: #1e1e1e"><code><span class="line"><span style="color: #d4d4d4">&lt;?php</span></span>

<span class="line"><span style="color: #c586c0">declare</span><span style="color: #d4d4d4">(strict_types=</span><span style="color: #b5cea8">1</span><span style="color: #d4d4d4">);</span></span>

<span class="line"><span style="color: #569cd6">namespace</span> <span style="color: #4ec9b0">RenorWatermark</span><span style="color: #d4d4d4">;</span></span>

<span class="line"><span style="color: #6a9955">/**</span></span>
<span class="line"><span style="color: #6a9955"> * Watermarker class</span></span>
<span class="line"><span style="color: #6a9955"> *</span></span>
<span class="line"><span style="color: #6a9955"> * Embeds/extracts a short ASCII message (max 10 characters + terminator)</span></span>
<span class="line"><span style="color: #6a9955"> * into low-frequency DCT coefficients. Instead of relying on the single</span></span>
<span class="line"><span style="color: #6a9955"> * parity bit – too fragile after rounding and quantization – here</span></span>
<span class="line"><span style="color: #6a9955"> * we encode the information into the **sign** of the coefficient:</span></span>
<span class="line"><span style="color: #6a9955"> *</span></span>
<span class="line"><span style="color: #6a9955"> *   bit 0  → positive coefficient</span></span>
<span class="line"><span style="color: #6a9955"> *   bit 1  → negative coefficient</span></span>
<span class="line"><span style="color: #6a9955"> *</span></span>
<span class="line"><span style="color: #6a9955"> * The sign is never affected during:</span></span>
<span class="line"><span style="color: #6a9955"> *   1. IDCT → integer rounding,</span></span>
<span class="line"><span style="color: #6a9955"> *   2. division by JPEG quantization tables,</span></span>
<span class="line"><span style="color: #6a9955"> *   3. further rounding or transformations.</span></span>
<span class="line"><span style="color: #6a9955"> */</span></span>
<span class="line"><span style="color: #569cd6">final</span> <span style="color: #569cd6">class</span> <span style="color: #4ec9b0">Watermarker</span></span>
<span class="line"><span style="color: #d4d4d4">{</span></span>
<span class="line">    <span style="color: #6a9955">/** Low-frequency coordinates (survive even at q≈90–100). */</span></span>
<span class="line">    <span style="color: #569cd6">private</span> <span style="color: #569cd6">const</span><span style="color: #d4d4d4"> EMBED_COORDS = [</span></span>
<span class="line"><span style="color: #d4d4d4">        [</span><span style="color: #b5cea8">0</span><span style="color: #d4d4d4">, </span><span style="color: #b5cea8">1</span><span style="color: #d4d4d4">], [</span><span style="color: #b5cea8">1</span><span style="color: #d4d4d4">, </span><span style="color: #b5cea8">0</span><span style="color: #d4d4d4">], [</span><span style="color: #b5cea8">1</span><span style="color: #d4d4d4">, </span><span style="color: #b5cea8">1</span><span style="color: #d4d4d4">], [</span><span style="color: #b5cea8">0</span><span style="color: #d4d4d4">, </span><span style="color: #b5cea8">2</span><span style="color: #d4d4d4">],</span></span>
<span class="line"><span style="color: #d4d4d4">        [</span><span style="color: #b5cea8">2</span><span style="color: #d4d4d4">, </span><span style="color: #b5cea8">0</span><span style="color: #d4d4d4">], [</span><span style="color: #b5cea8">1</span><span style="color: #d4d4d4">, </span><span style="color: #b5cea8">2</span><span style="color: #d4d4d4">], [</span><span style="color: #b5cea8">2</span><span style="color: #d4d4d4">, </span><span style="color: #b5cea8">1</span><span style="color: #d4d4d4">], [</span><span style="color: #b5cea8">2</span><span style="color: #d4d4d4">, </span><span style="color: #b5cea8">2</span><span style="color: #d4d4d4">]</span></span>
<span class="line"><span style="color: #d4d4d4">    ];</span></span>

<span class="line">    <span style="color: #6a9955">/** Redundancy: each bit is repeated 25 times. */</span></span>
<span class="line">    <span style="color: #569cd6">private</span> <span style="color: #569cd6">const</span><span style="color: #d4d4d4"> REDUNDANCY = </span><span style="color: #b5cea8">25</span><span style="color: #d4d4d4">;</span></span>

<span class="line">    <span style="color: #569cd6">private</span> <span style="color: #569cd6">const</span><span style="color: #d4d4d4"> TERMINATOR = </span><span style="color: #ce9178">"</span><span style="color: #d7ba7d"></span><span style="color: #ce9178">"</span><span style="color: #d4d4d4">;</span></span>

<span class="line">    <span style="color: #6a9955">/* ------------------------------------------------------------------</span></span>
<span class="line"><span style="color: #6a9955">       Public API</span></span>
<span class="line"><span style="color: #6a9955">    -------------------------------------------------------------------*/</span></span>

<span class="line">    <span style="color: #569cd6">public</span> <span style="color: #569cd6">static</span> <span style="color: #569cd6">function</span> <span style="color: #dcdcaa">embed</span><span style="color: #d4d4d4">(</span><span style="color: #569cd6">array</span> <span style="color: #569cd6">&amp;</span><span style="color: #9cdcfe">$blocks</span><span style="color: #d4d4d4">, </span><span style="color: #569cd6">string</span> <span style="color: #9cdcfe">$msg</span><span style="color: #d4d4d4">): </span><span style="color: #569cd6">void</span></span>
<span class="line"><span style="color: #d4d4d4">    {</span></span>
<span class="line">        <span style="color: #c586c0">if</span><span style="color: #d4d4d4"> (</span><span style="color: #dcdcaa">strlen</span><span style="color: #d4d4d4">(</span><span style="color: #9cdcfe">$msg</span><span style="color: #d4d4d4">) &gt; </span><span style="color: #b5cea8">10</span><span style="color: #d4d4d4">) {</span></span>
<span class="line">            <span style="color: #c586c0">throw</span> <span style="color: #569cd6">new</span> <span style="color: #4ec9b0">RuntimeException</span><span style="color: #d4d4d4">(</span><span style="color: #ce9178">'Message too long (max 10).'</span><span style="color: #d4d4d4">);</span></span>
<span class="line"><span style="color: #d4d4d4">        }</span></span>

<span class="line">        <span style="color: #9cdcfe">$bits</span><span style="color: #d4d4d4">   = </span><span style="color: #569cd6">self</span><span style="color: #d4d4d4">::</span><span style="color: #dcdcaa">stringToBitStream</span><span style="color: #d4d4d4">(</span><span style="color: #9cdcfe">$msg</span> <span style="color: #d4d4d4">.</span> <span style="color: #569cd6">self</span><span style="color: #d4d4d4">::TERMINATOR);</span></span>
<span class="line">        <span style="color: #9cdcfe">$cursor</span><span style="color: #d4d4d4"> = </span><span style="color: #b5cea8">0</span><span style="color: #d4d4d4">;</span></span>

<span class="line">        <span style="color: #c586c0">foreach</span><span style="color: #d4d4d4"> (</span><span style="color: #9cdcfe">$blocks</span><span style="color: #d4d4d4"> as </span><span style="color: #569cd6">&amp;</span><span style="color: #9cdcfe">$block</span><span style="color: #d4d4d4">) {</span></span>
<span class="line">            <span style="color: #c586c0">foreach</span><span style="color: #d4d4d4"> (</span><span style="color: #569cd6">self</span><span style="color: #d4d4d4">::EMBED_COORDS as [</span><span style="color: #9cdcfe">$u</span><span style="color: #d4d4d4">, </span><span style="color: #9cdcfe">$v</span><span style="color: #d4d4d4">]) {</span></span>
<span class="line">                <span style="color: #c586c0">if</span><span style="color: #d4d4d4"> (</span><span style="color: #9cdcfe">$cursor</span><span style="color: #d4d4d4"> &gt;= </span><span style="color: #dcdcaa">count</span><span style="color: #d4d4d4">(</span><span style="color: #9cdcfe">$bits</span><span style="color: #d4d4d4">)) {</span></span>
<span class="line">                    <span style="color: #c586c0">return</span><span style="color: #d4d4d4">;</span></span>
<span class="line"><span style="color: #d4d4d4">                }</span></span>
<span class="line">                <span style="color: #9cdcfe">$bit</span><span style="color: #d4d4d4">           = </span><span style="color: #9cdcfe">$bits</span><span style="color: #d4d4d4">[</span><span style="color: #9cdcfe">$cursor</span><span style="color: #d4d4d4">++];</span></span>
<span class="line">                <span style="color: #9cdcfe">$block</span><span style="color: #d4d4d4">[</span><span style="color: #9cdcfe">$u</span><span style="color: #d4d4d4">][</span><span style="color: #9cdcfe">$v</span><span style="color: #d4d4d4">] = </span><span style="color: #569cd6">self</span><span style="color: #d4d4d4">::</span><span style="color: #dcdcaa">forceSign</span><span style="color: #d4d4d4">(</span><span style="color: #9cdcfe">$block</span><span style="color: #d4d4d4">[</span><span style="color: #9cdcfe">$u</span><span style="color: #d4d4d4">][</span><span style="color: #9cdcfe">$v</span><span style="color: #d4d4d4">], </span><span style="color: #9cdcfe">$bit</span><span style="color: #d4d4d4">);</span></span>
<span class="line"><span style="color: #d4d4d4">            }</span></span>
<span class="line"><span style="color: #d4d4d4">        }</span></span>
<span class="line">        <span style="color: #c586c0">if</span><span style="color: #d4d4d4"> (</span><span style="color: #9cdcfe">$cursor</span><span style="color: #d4d4d4"> &lt; </span><span style="color: #dcdcaa">count</span><span style="color: #d4d4d4">(</span><span style="color: #9cdcfe">$bits</span><span style="color: #d4d4d4">)) {</span></span>
<span class="line">            <span style="color: #c586c0">throw</span> <span style="color: #569cd6">new</span> <span style="color: #4ec9b0">RuntimeException</span><span style="color: #d4d4d4">(</span><span style="color: #ce9178">'Image too small for the message.'</span><span style="color: #d4d4d4">);</span></span>
<span class="line"><span style="color: #d4d4d4">        }</span></span>
<span class="line"><span style="color: #d4d4d4">    }</span></span>

<span class="line">    <span style="color: #569cd6">public</span> <span style="color: #569cd6">static</span> <span style="color: #569cd6">function</span> <span style="color: #dcdcaa">extract</span><span style="color: #d4d4d4">(</span><span style="color: #569cd6">array</span> <span style="color: #9cdcfe">$blocks</span><span style="color: #d4d4d4">): </span><span style="color: #569cd6">string</span></span>
<span class="line"><span style="color: #d4d4d4">    {</span></span>
<span class="line">        <span style="color: #9cdcfe">$bits</span><span style="color: #d4d4d4"> = [];</span></span>
<span class="line">        <span style="color: #c586c0">foreach</span><span style="color: #d4d4d4"> (</span><span style="color: #9cdcfe">$blocks</span><span style="color: #d4d4d4"> as </span><span style="color: #9cdcfe">$block</span><span style="color: #d4d4d4">) {</span></span>
<span class="line">            <span style="color: #c586c0">foreach</span><span style="color: #d4d4d4"> (</span><span style="color: #569cd6">self</span><span style="color: #d4d4d4">::EMBED_COORDS as [</span><span style="color: #9cdcfe">$u</span><span style="color: #d4d4d4">, </span><span style="color: #9cdcfe">$v</span><span style="color: #d4d4d4">]) {</span></span>
<span class="line">                <span style="color: #9cdcfe">$bits</span><span style="color: #d4d4d4">[] = ( (</span><span style="color: #569cd6">int</span><span style="color: #d4d4d4">) </span><span style="color: #dcdcaa">round</span><span style="color: #d4d4d4">(</span><span style="color: #9cdcfe">$block</span><span style="color: #d4d4d4">[</span><span style="color: #9cdcfe">$u</span><span style="color: #d4d4d4">][</span><span style="color: #9cdcfe">$v</span><span style="color: #d4d4d4">]) &lt; </span><span style="color: #b5cea8">0</span><span style="color: #d4d4d4"> ) ? </span><span style="color: #b5cea8">1</span><span style="color: #d4d4d4"> : </span><span style="color: #b5cea8">0</span><span style="color: #d4d4d4">;</span></span>
<span class="line"><span style="color: #d4d4d4">            }</span></span>
<span class="line"><span style="color: #d4d4d4">        }</span></span>

<span class="line">        <span style="color: #9cdcfe">$filtered</span><span style="color: #d4d4d4">   = </span><span style="color: #569cd6">self</span><span style="color: #d4d4d4">::</span><span style="color: #dcdcaa">majority</span><span style="color: #d4d4d4">(</span><span style="color: #9cdcfe">$bits</span><span style="color: #d4d4d4">, </span><span style="color: #569cd6">self</span><span style="color: #d4d4d4">::REDUNDANCY);</span></span>
<span class="line">        <span style="color: #9cdcfe">$byteChunks</span><span style="color: #d4d4d4"> = </span><span style="color: #dcdcaa">array_chunk</span><span style="color: #d4d4d4">(</span><span style="color: #9cdcfe">$filtered</span><span style="color: #d4d4d4">, </span><span style="color: #b5cea8">8</span><span style="color: #d4d4d4">);</span></span>

<span class="line">        <span style="color: #9cdcfe">$out</span><span style="color: #d4d4d4"> = </span><span style="color: #ce9178">''</span><span style="color: #d4d4d4">;</span></span>
<span class="line">        <span style="color: #c586c0">foreach</span><span style="color: #d4d4d4"> (</span><span style="color: #9cdcfe">$byteChunks</span><span style="color: #d4d4d4"> as </span><span style="color: #9cdcfe">$chunk</span><span style="color: #d4d4d4">) {</span></span>
<span class="line">            <span style="color: #c586c0">if</span><span style="color: #d4d4d4"> (</span><span style="color: #dcdcaa">count</span><span style="color: #d4d4d4">(</span><span style="color: #9cdcfe">$chunk</span><span style="color: #d4d4d4">) &lt; </span><span style="color: #b5cea8">8</span><span style="color: #d4d4d4">) </span><span style="color: #c586c0">break</span><span style="color: #d4d4d4">;</span></span>
<span class="line">            <span style="color: #9cdcfe">$ch</span><span style="color: #d4d4d4"> = </span><span style="color: #dcdcaa">chr</span><span style="color: #d4d4d4">(</span><span style="color: #569cd6">self</span><span style="color: #d4d4d4">::</span><span style="color: #dcdcaa">bitsToInt</span><span style="color: #d4d4d4">(</span><span style="color: #9cdcfe">$chunk</span><span style="color: #d4d4d4">));</span></span>
<span class="line">            <span style="color: #c586c0">if</span><span style="color: #d4d4d4"> (</span><span style="color: #9cdcfe">$ch</span><span style="color: #d4d4d4"> === </span><span style="color: #569cd6">self</span><span style="color: #d4d4d4">::TERMINATOR) </span><span style="color: #c586c0">break</span><span style="color: #d4d4d4">;</span></span>
<span class="line">            <span style="color: #9cdcfe">$out</span> <span style="color: #d4d4d4">.=</span> <span style="color: #9cdcfe">$ch</span><span style="color: #d4d4d4">;</span></span>
<span class="line"><span style="color: #d4d4d4">        }</span></span>
<span class="line">        <span style="color: #c586c0">return</span> <span style="color: #9cdcfe">$out</span><span style="color: #d4d4d4">;</span></span>
<span class="line"><span style="color: #d4d4d4">    }</span></span>

<span class="line">    <span style="color: #6a9955">/* ------------------------------------------------------------------</span></span>
<span class="line"><span style="color: #6a9955">       Private helpers</span></span>
<span class="line"><span style="color: #6a9955">    -------------------------------------------------------------------*/</span></span>

<span class="line">    <span style="color: #569cd6">private</span> <span style="color: #569cd6">static</span> <span style="color: #569cd6">function</span> <span style="color: #dcdcaa">stringToBitStream</span><span style="color: #d4d4d4">(</span><span style="color: #569cd6">string</span> <span style="color: #9cdcfe">$s</span><span style="color: #d4d4d4">): </span><span style="color: #569cd6">array</span></span>
<span class="line"><span style="color: #d4d4d4">    {</span></span>
<span class="line">        <span style="color: #9cdcfe">$bits</span><span style="color: #d4d4d4"> = [];</span></span>
<span class="line">        <span style="color: #c586c0">foreach</span><span style="color: #d4d4d4"> (</span><span style="color: #dcdcaa">str_split</span><span style="color: #d4d4d4">(</span><span style="color: #9cdcfe">$s</span><span style="color: #d4d4d4">) as </span><span style="color: #9cdcfe">$c</span><span style="color: #d4d4d4">) {</span></span>
<span class="line">            <span style="color: #9cdcfe">$byte</span><span style="color: #d4d4d4"> = </span><span style="color: #dcdcaa">ord</span><span style="color: #d4d4d4">(</span><span style="color: #9cdcfe">$c</span><span style="color: #d4d4d4">);</span></span>
<span class="line">            <span style="color: #c586c0">for</span><span style="color: #d4d4d4"> (</span><span style="color: #9cdcfe">$i</span><span style="color: #d4d4d4"> = </span><span style="color: #b5cea8">7</span><span style="color: #d4d4d4">; </span><span style="color: #9cdcfe">$i</span><span style="color: #d4d4d4"> &gt;= </span><span style="color: #b5cea8">0</span><span style="color: #d4d4d4">; --</span><span style="color: #9cdcfe">$i</span><span style="color: #d4d4d4">) {</span></span>
<span class="line">                <span style="color: #9cdcfe">$bit</span><span style="color: #d4d4d4"> = (</span><span style="color: #9cdcfe">$byte</span><span style="color: #d4d4d4"> &gt;&gt; </span><span style="color: #9cdcfe">$i</span><span style="color: #d4d4d4">) &amp; </span><span style="color: #b5cea8">1</span><span style="color: #d4d4d4">;</span></span>
<span class="line">                <span style="color: #9cdcfe">$bits</span><span style="color: #d4d4d4"> = </span><span style="color: #dcdcaa">array_merge</span><span style="color: #d4d4d4">(</span><span style="color: #9cdcfe">$bits</span><span style="color: #d4d4d4">, </span><span style="color: #dcdcaa">array_fill</span><span style="color: #d4d4d4">(</span><span style="color: #b5cea8">0</span><span style="color: #d4d4d4">, </span><span style="color: #569cd6">self</span><span style="color: #d4d4d4">::REDUNDANCY, </span><span style="color: #9cdcfe">$bit</span><span style="color: #d4d4d4">));</span></span>
<span class="line"><span style="color: #d4d4d4">            }</span></span>
<span class="line"><span style="color: #d4d4d4">        }</span></span>
<span class="line">        <span style="color: #c586c0">return</span> <span style="color: #9cdcfe">$bits</span><span style="color: #d4d4d4">;</span></span>
<span class="line"><span style="color: #d4d4d4">    }</span></span>

<span class="line">    <span style="color: #569cd6">private</span> <span style="color: #569cd6">static</span> <span style="color: #569cd6">function</span> <span style="color: #dcdcaa">majority</span><span style="color: #d4d4d4">(</span><span style="color: #569cd6">array</span> <span style="color: #9cdcfe">$bits</span><span style="color: #d4d4d4">, </span><span style="color: #569cd6">int</span> <span style="color: #9cdcfe">$group</span><span style="color: #d4d4d4">): </span><span style="color: #569cd6">array</span></span>
<span class="line"><span style="color: #d4d4d4">    {</span></span>
<span class="line">        <span style="color: #9cdcfe">$out</span><span style="color: #d4d4d4"> = [];</span></span>
<span class="line">        <span style="color: #c586c0">foreach</span><span style="color: #d4d4d4"> (</span><span style="color: #dcdcaa">array_chunk</span><span style="color: #d4d4d4">(</span><span style="color: #9cdcfe">$bits</span><span style="color: #d4d4d4">, </span><span style="color: #9cdcfe">$group</span><span style="color: #d4d4d4">) as </span><span style="color: #9cdcfe">$chunk</span><span style="color: #d4d4d4">) {</span></span>
<span class="line">            <span style="color: #9cdcfe">$out</span><span style="color: #d4d4d4">[] = (</span><span style="color: #dcdcaa">array_sum</span><span style="color: #d4d4d4">(</span><span style="color: #9cdcfe">$chunk</span><span style="color: #d4d4d4">) &gt; </span><span style="color: #9cdcfe">$group</span><span style="color: #d4d4d4"> / </span><span style="color: #b5cea8">2</span><span style="color: #d4d4d4">) ? </span><span style="color: #b5cea8">1</span><span style="color: #d4d4d4"> : </span><span style="color: #b5cea8">0</span><span style="color: #d4d4d4">;</span></span>
<span class="line"><span style="color: #d4d4d4">        }</span></span>
<span class="line">        <span style="color: #c586c0">return</span> <span style="color: #9cdcfe">$out</span><span style="color: #d4d4d4">;</span></span>
<span class="line"><span style="color: #d4d4d4">    }</span></span>

<span class="line">    <span style="color: #569cd6">private</span> <span style="color: #569cd6">static</span> <span style="color: #569cd6">function</span> <span style="color: #dcdcaa">bitsToInt</span><span style="color: #d4d4d4">(</span><span style="color: #569cd6">array</span> <span style="color: #9cdcfe">$bits</span><span style="color: #d4d4d4">): </span><span style="color: #569cd6">int</span></span>
<span class="line"><span style="color: #d4d4d4">    {</span></span>
<span class="line">        <span style="color: #c586c0">return</span> <span style="color: #dcdcaa">array_reduce</span><span style="color: #d4d4d4">(</span><span style="color: #9cdcfe">$bits</span><span style="color: #d4d4d4">, </span><span style="color: #569cd6">fn</span><span style="color: #d4d4d4">(</span><span style="color: #9cdcfe">$v</span><span style="color: #d4d4d4">, </span><span style="color: #9cdcfe">$b</span><span style="color: #d4d4d4">) =&gt; (</span><span style="color: #9cdcfe">$v</span><span style="color: #d4d4d4"> &lt;&lt; </span><span style="color: #b5cea8">1</span><span style="color: #d4d4d4">) | </span><span style="color: #9cdcfe">$b</span><span style="color: #d4d4d4">, </span><span style="color: #b5cea8">0</span><span style="color: #d4d4d4">);</span></span>
<span class="line"><span style="color: #d4d4d4">    }</span></span>

<span class="line">    <span style="color: #6a9955">/**</span></span>
<span class="line"><span style="color: #6a9955">     * Forces the sign of the coefficient:</span></span>
<span class="line"><span style="color: #6a9955">     *   bit 0 → positive   (&gt;= +minAmp)</span></span>
<span class="line"><span style="color: #6a9955">     *   bit 1 → negative   (&lt;= -minAmp)</span></span>
<span class="line"><span style="color: #6a9955">     * so the quantizer cannot flip it.</span></span>
<span class="line"><span style="color: #6a9955">     */</span></span>
<span class="line">    <span style="color: #569cd6">private</span> <span style="color: #569cd6">static</span> <span style="color: #569cd6">function</span> <span style="color: #dcdcaa">forceSign</span><span style="color: #d4d4d4">(</span></span>
<span class="line">        <span style="color: #569cd6">float</span> <span style="color: #9cdcfe">$coeff</span><span style="color: #d4d4d4">,</span></span>
<span class="line">        <span style="color: #569cd6">int</span>   <span style="color: #9cdcfe">$bit</span><span style="color: #d4d4d4">,</span></span>
<span class="line">        <span style="color: #569cd6">int</span>   <span style="color: #9cdcfe">$minAmp</span><span style="color: #d4d4d4"> = </span><span style="color: #b5cea8">80</span><span style="color: #d4d4d4">,   </span><span style="color: #6a9955">// safe amplitude &gt; luminance quantization divisors</span></span>
<span class="line">        <span style="color: #569cd6">int</span>   <span style="color: #9cdcfe">$boost</span><span style="color: #d4d4d4">  = </span><span style="color: #b5cea8">64</span>    <span style="color: #6a9955">// further offset to move away from zero</span></span>
<span class="line"><span style="color: #d4d4d4">    ): </span><span style="color: #569cd6">float</span><span style="color: #d4d4d4"> {</span></span>
<span class="line">        <span style="color: #9cdcfe">$rounded</span><span style="color: #d4d4d4"> = (</span><span style="color: #569cd6">int</span><span style="color: #d4d4d4">) </span><span style="color: #dcdcaa">round</span><span style="color: #d4d4d4">(</span><span style="color: #9cdcfe">$coeff</span><span style="color: #d4d4d4">);</span></span>

<span class="line">        <span style="color: #6a9955">// Enforce minimum amplitude</span></span>
<span class="line">        <span style="color: #c586c0">if</span><span style="color: #d4d4d4"> (</span><span style="color: #dcdcaa">abs</span><span style="color: #d4d4d4">(</span><span style="color: #9cdcfe">$rounded</span><span style="color: #d4d4d4">) &lt; </span><span style="color: #9cdcfe">$minAmp</span><span style="color: #d4d4d4">) {</span></span>
<span class="line">            <span style="color: #9cdcfe">$rounded</span><span style="color: #d4d4d4"> = (</span><span style="color: #9cdcfe">$rounded</span><span style="color: #d4d4d4"> &gt;= </span><span style="color: #b5cea8">0</span><span style="color: #d4d4d4">) ? </span><span style="color: #9cdcfe">$minAmp</span><span style="color: #d4d4d4"> : -</span><span style="color: #9cdcfe">$minAmp</span><span style="color: #d4d4d4">;</span></span>
<span class="line"><span style="color: #d4d4d4">        }</span></span>

<span class="line">        <span style="color: #6a9955">// Set the sign according to the bit</span></span>
<span class="line">        <span style="color: #c586c0">if</span><span style="color: #d4d4d4"> (</span><span style="color: #9cdcfe">$bit</span><span style="color: #d4d4d4"> === </span><span style="color: #b5cea8">0</span><span style="color: #d4d4d4"> &amp;&amp; </span><span style="color: #9cdcfe">$rounded</span><span style="color: #d4d4d4"> &lt; </span><span style="color: #b5cea8">0</span><span style="color: #d4d4d4">) </span><span style="color: #9cdcfe">$rounded</span><span style="color: #d4d4d4"> = </span><span style="color: #dcdcaa">abs</span><span style="color: #d4d4d4">(</span><span style="color: #9cdcfe">$rounded</span><span style="color: #d4d4d4">);</span></span>
<span class="line">        <span style="color: #c586c0">if</span><span style="color: #d4d4d4"> (</span><span style="color: #9cdcfe">$bit</span><span style="color: #d4d4d4"> === </span><span style="color: #b5cea8">1</span><span style="color: #d4d4d4"> &amp;&amp; </span><span style="color: #9cdcfe">$rounded</span><span style="color: #d4d4d4"> &gt; </span><span style="color: #b5cea8">0</span><span style="color: #d4d4d4">) </span><span style="color: #9cdcfe">$rounded</span><span style="color: #d4d4d4"> = -</span><span style="color: #9cdcfe">$rounded</span><span style="color: #d4d4d4">;</span></span>

<span class="line">        <span style="color: #6a9955">// Push further from zero: +/-boost (preserving the sign)</span></span>
<span class="line">        <span style="color: #9cdcfe">$rounded</span><span style="color: #d4d4d4"> += (</span><span style="color: #9cdcfe">$rounded</span><span style="color: #d4d4d4"> &gt; </span><span style="color: #b5cea8">0</span><span style="color: #d4d4d4">) ? </span><span style="color: #9cdcfe">$boost</span><span style="color: #d4d4d4"> : -</span><span style="color: #9cdcfe">$boost</span><span style="color: #d4d4d4">;</span></span>

<span class="line">        <span style="color: #c586c0">return</span><span style="color: #d4d4d4"> (</span><span style="color: #569cd6">float</span><span style="color: #d4d4d4">) </span><span style="color: #9cdcfe">$rounded</span><span style="color: #d4d4d4">;</span></span>
<span class="line"><span style="color: #d4d4d4">    }</span></span>

<span class="line">    <span style="color: #569cd6">private</span> <span style="color: #569cd6">function</span> <span style="color: #dcdcaa">__construct</span><span style="color: #d4d4d4">() {}</span></span>
<span class="line"><span style="color: #d4d4d4">}</span></span></code></pre>
</div>


<p>Quando viene invocato il metodo embed, il chiamante le passa l’array dei blocchi DCT e il messaggio da inserire. Il metodo trasforma ogni carattere in 8 bit, e ciascun bit viene replicato 25 volte (come specificato dalla costante REDUNDANCY), così da poter essere letto con un voto di maggioranza e resistere ad alterazioni dovute alla compressione JPEG. Il flusso così ridondato scorre blocco dopo blocco e si appoggia su 8 coordinate a <strong>bassa frequenza</strong>, definite nell’array costante EMBED_COORDS. Queste posizioni sono state scelte perché non intaccano la percezione visiva ma tendono a sopravvivere anche a compressioni JPEG moderate (qualità 60–80).</p>
<p>Per ogni coefficiente selezionato, la funzione privata forceSign() impone un segno al coefficiente: positivo per rappresentare 0, negativo per rappresentare 1. Questo approccio, più robusto rispetto all’uso della parità, garantisce che l’informazione rimanga leggibile anche dopo un passaggio di quantizzazione JPEG. Se l’immagine non contiene abbastanza blocchi per rappresentare l’intero messaggio, viene lanciata un’eccezione con un messaggio esplicito.</p>
<p>Il percorso inverso è affidato al metodo extract. Anche qui, la classe legge il segno degli stessi 8 coefficienti in ogni blocco, ricostruendo un lungo vettore di zeri e uno. I bit vengono poi raggruppati secondo la ridondanza e passano attraverso una funzione di voto di maggioranza (majority()), che recupera il singolo bit originario. Ogni gruppo di 8 bit restituisce un carattere, fino a incontrare il terminatore NUL che segnala la fine del messaggio. L’insieme dei caratteri così ottenuti forma il messaggio originale.</p>
<p>Le funzioni di supporto stringToBitStream, bitsToInt e majority incapsulano i dettagli binari, lasciando i metodi pubblici brevi e leggibili. Come la classe Dct, anche Watermarker è priva di stato interno e non può essere istanziata: tutti i metodi sono statici. Questo approccio funzionale facilita i test automatici e l’uso in ambienti concorrenti. In sintesi, la classe Watermarker realizza concretamente i principi matematici descritti in precedenza: ridondanza ciclica, codifica del bit tramite segno, terminazione esplicita del messaggio, in un flusso compatto e robusto pensato per sopravvivere alle trasformazioni tipiche delle immagini pubblicate online.</p>
<h2 class="wp-block-heading">ImageIO: dall&#8217;immagine ai blocchi DCT e ritorno</h2>
<p>La classe ImageIO è il ponte tra la teoria matematica e il file JPEG concreto.</p>


<div class="wp-block-kevinbatdorf-code-block-pro" style="font-size: .875rem;font-family: Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height: 1.25rem;--cbp-tab-width: 2" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono">
<pre class="shiki dark-plus" style="background-color: #1e1e1e"><code><span class="line"><span style="color: #d4d4d4">&lt;?php</span></span>

<span class="line"><span style="color: #c586c0">declare</span><span style="color: #d4d4d4">(strict_types=</span><span style="color: #b5cea8">1</span><span style="color: #d4d4d4">);</span></span>

<span class="line"><span style="color: #569cd6">namespace</span> <span style="color: #4ec9b0">RenorWatermark</span><span style="color: #d4d4d4">;</span></span>

<span class="line"><span style="color: #569cd6">use</span> <span style="color: #4ec9b0">GdImage</span><span style="color: #d4d4d4">;</span></span>

<span class="line"><span style="color: #6a9955">/**</span></span>
<span class="line"><span style="color: #6a9955"> * Class ImageIO</span></span>
<span class="line"><span style="color: #6a9955"> *</span></span>
<span class="line"><span style="color: #6a9955"> * - Loads a JPEG image.</span></span>
<span class="line"><span style="color: #6a9955"> * - Converts RGB to the Y (luminance) channel.</span></span>
<span class="line"><span style="color: #6a9955"> * - Splits it into 8x8 blocks and applies DCT/IDCT.</span></span>
<span class="line"><span style="color: #6a9955"> * - Overwrites the Y channel with the embedded watermark, merging with the original CbCr.</span></span>
<span class="line"><span style="color: #6a9955"> * - Saves the final image as JPEG with a specified quality.</span></span>
<span class="line"><span style="color: #6a9955"> */</span></span>
<span class="line"><span style="color: #569cd6">final</span> <span style="color: #569cd6">class</span> <span style="color: #4ec9b0">ImageIO</span></span>
<span class="line"><span style="color: #d4d4d4">{</span></span>
<span class="line">    <span style="color: #569cd6">private</span> <span style="color: #569cd6">const</span><span style="color: #d4d4d4"> BLOCK_SIZE = </span><span style="color: #b5cea8">8</span><span style="color: #d4d4d4">;</span></span>
<span class="line">    <span style="color: #569cd6">private</span> <span style="color: #569cd6">const</span><span style="color: #d4d4d4"> MIN_WIDTH = </span><span style="color: #b5cea8">200</span><span style="color: #d4d4d4">;</span></span>
<span class="line">    <span style="color: #569cd6">private</span> <span style="color: #569cd6">const</span><span style="color: #d4d4d4"> MIN_HEIGHT = </span><span style="color: #b5cea8">200</span><span style="color: #d4d4d4">;</span></span>

<span class="line">    <span style="color: #6a9955">/**</span></span>
<span class="line"><span style="color: #6a9955">     * Embed a watermark in a JPEG image and save the result.</span></span>
<span class="line"><span style="color: #6a9955">     *</span></span>
<span class="line"><span style="color: #6a9955">     * </span><span style="color: #569cd6">@param</span> <span style="color: #569cd6">string</span><span style="color: #6a9955"> $src      Path to the original JPEG</span></span>
<span class="line"><span style="color: #6a9955">     * </span><span style="color: #569cd6">@param</span> <span style="color: #569cd6">string</span><span style="color: #6a9955"> $dest     Output path for the watermarked image</span></span>
<span class="line"><span style="color: #6a9955">     * </span><span style="color: #569cd6">@param</span> <span style="color: #569cd6">string</span><span style="color: #6a9955"> $message  ASCII watermark (up to 10 chars)</span></span>
<span class="line"><span style="color: #6a9955">     * </span><span style="color: #569cd6">@param</span> <span style="color: #569cd6">int</span><span style="color: #6a9955">    $quality  JPEG quality in [0..100], default 90</span></span>
<span class="line"><span style="color: #6a9955">     */</span></span>
<span class="line">    <span style="color: #569cd6">public</span> <span style="color: #569cd6">static</span> <span style="color: #569cd6">function</span> <span style="color: #dcdcaa">embed</span><span style="color: #d4d4d4">(</span></span>
<span class="line">        <span style="color: #569cd6">string</span> <span style="color: #9cdcfe">$src</span><span style="color: #d4d4d4">,</span></span>
<span class="line">        <span style="color: #569cd6">string</span> <span style="color: #9cdcfe">$dest</span><span style="color: #d4d4d4">,</span></span>
<span class="line">        <span style="color: #569cd6">string</span> <span style="color: #9cdcfe">$message</span><span style="color: #d4d4d4">,</span></span>
<span class="line">        <span style="color: #569cd6">int</span> <span style="color: #9cdcfe">$quality</span><span style="color: #d4d4d4"> = </span><span style="color: #b5cea8">90</span></span>
<span class="line"><span style="color: #d4d4d4">    ): </span><span style="color: #569cd6">void</span><span style="color: #d4d4d4"> {</span></span>
<span class="line">        <span style="color: #9cdcfe">$im</span><span style="color: #d4d4d4"> = </span><span style="color: #569cd6">self</span><span style="color: #d4d4d4">::</span><span style="color: #dcdcaa">loadJpeg</span><span style="color: #d4d4d4">(</span><span style="color: #9cdcfe">$src</span><span style="color: #d4d4d4">);</span></span>
<span class="line">        <span style="color: #9cdcfe">$w</span><span style="color: #d4d4d4"> = </span><span style="color: #dcdcaa">imagesx</span><span style="color: #d4d4d4">(</span><span style="color: #9cdcfe">$im</span><span style="color: #d4d4d4">);</span></span>
<span class="line">        <span style="color: #9cdcfe">$h</span><span style="color: #d4d4d4"> = </span><span style="color: #dcdcaa">imagesy</span><span style="color: #d4d4d4">(</span><span style="color: #9cdcfe">$im</span><span style="color: #d4d4d4">);</span></span>

<span class="line">        <span style="color: #6a9955">// Ensure a minimum image size</span></span>
<span class="line">        <span style="color: #c586c0">if</span><span style="color: #d4d4d4"> (</span><span style="color: #9cdcfe">$w</span><span style="color: #d4d4d4"> &lt; </span><span style="color: #569cd6">self</span><span style="color: #d4d4d4">::MIN_WIDTH || </span><span style="color: #9cdcfe">$h</span><span style="color: #d4d4d4"> &lt; </span><span style="color: #569cd6">self</span><span style="color: #d4d4d4">::MIN_HEIGHT) {</span></span>
<span class="line">            <span style="color: #dcdcaa">imagedestroy</span><span style="color: #d4d4d4">(</span><span style="color: #9cdcfe">$im</span><span style="color: #d4d4d4">);</span></span>
<span class="line">            <span style="color: #c586c0">throw</span> <span style="color: #569cd6">new</span> <span style="color: #4ec9b0">RuntimeException</span><span style="color: #d4d4d4">(</span><span style="color: #ce9178">"Image must be at least 200x200 for robust embedding."</span><span style="color: #d4d4d4">);</span></span>
<span class="line"><span style="color: #d4d4d4">        }</span></span>

<span class="line">        <span style="color: #6a9955">// Convert RGB → Y</span></span>
<span class="line">        <span style="color: #9cdcfe">$Y</span><span style="color: #d4d4d4"> = </span><span style="color: #569cd6">self</span><span style="color: #d4d4d4">::</span><span style="color: #dcdcaa">rgbToY</span><span style="color: #d4d4d4">(</span><span style="color: #9cdcfe">$im</span><span style="color: #d4d4d4">);</span></span>

<span class="line">        <span style="color: #6a9955">// Split into 8x8 blocks, apply forward DCT</span></span>
<span class="line">        <span style="color: #9cdcfe">$blocks</span><span style="color: #d4d4d4"> = </span><span style="color: #569cd6">self</span><span style="color: #d4d4d4">::</span><span style="color: #dcdcaa">forwardBlocks</span><span style="color: #d4d4d4">(</span><span style="color: #9cdcfe">$Y</span><span style="color: #d4d4d4">, </span><span style="color: #9cdcfe">$w</span><span style="color: #d4d4d4">, </span><span style="color: #9cdcfe">$h</span><span style="color: #d4d4d4">);</span></span>

<span class="line">        <span style="color: #6a9955">// Embed the message into the DCT coefficients</span></span>
<span class="line">        <span style="color: #4ec9b0">Watermarker</span><span style="color: #d4d4d4">::</span><span style="color: #dcdcaa">embed</span><span style="color: #d4d4d4">(</span><span style="color: #9cdcfe">$blocks</span><span style="color: #d4d4d4">, </span><span style="color: #9cdcfe">$message</span><span style="color: #d4d4d4">);</span></span>

<span class="line">        <span style="color: #6a9955">// Reconstruct the Y channel from the inverse DCT</span></span>
<span class="line">        <span style="color: #9cdcfe">$Ywm</span><span style="color: #d4d4d4"> = </span><span style="color: #569cd6">self</span><span style="color: #d4d4d4">::</span><span style="color: #dcdcaa">inverseBlocks</span><span style="color: #d4d4d4">(</span><span style="color: #9cdcfe">$blocks</span><span style="color: #d4d4d4">, </span><span style="color: #9cdcfe">$w</span><span style="color: #d4d4d4">, </span><span style="color: #9cdcfe">$h</span><span style="color: #d4d4d4">);</span></span>

<span class="line">        <span style="color: #6a9955">// Merge the modified Y channel and save as JPEG</span></span>
<span class="line">        <span style="color: #569cd6">self</span><span style="color: #d4d4d4">::</span><span style="color: #dcdcaa">mergeAndSave</span><span style="color: #d4d4d4">(</span><span style="color: #9cdcfe">$im</span><span style="color: #d4d4d4">, </span><span style="color: #9cdcfe">$Ywm</span><span style="color: #d4d4d4">, </span><span style="color: #9cdcfe">$dest</span><span style="color: #d4d4d4">, </span><span style="color: #9cdcfe">$quality</span><span style="color: #d4d4d4">);</span></span>

<span class="line">        <span style="color: #dcdcaa">imagedestroy</span><span style="color: #d4d4d4">(</span><span style="color: #9cdcfe">$im</span><span style="color: #d4d4d4">);</span></span>
<span class="line"><span style="color: #d4d4d4">    }</span></span>

<span class="line">    <span style="color: #6a9955">/**</span></span>
<span class="line"><span style="color: #6a9955">     * Extract the watermark from a JPEG image.</span></span>
<span class="line"><span style="color: #6a9955">     *</span></span>
<span class="line"><span style="color: #6a9955">     * </span><span style="color: #569cd6">@param</span> <span style="color: #569cd6">string</span><span style="color: #6a9955"> $src Path to the watermarked JPEG</span></span>
<span class="line"><span style="color: #6a9955">     * </span><span style="color: #569cd6">@return</span> <span style="color: #569cd6">string</span><span style="color: #6a9955">     The recovered ASCII message</span></span>
<span class="line"><span style="color: #6a9955">     */</span></span>
<span class="line">    <span style="color: #569cd6">public</span> <span style="color: #569cd6">static</span> <span style="color: #569cd6">function</span> <span style="color: #dcdcaa">extract</span><span style="color: #d4d4d4">(</span><span style="color: #569cd6">string</span> <span style="color: #9cdcfe">$src</span><span style="color: #d4d4d4">): </span><span style="color: #569cd6">string</span></span>
<span class="line"><span style="color: #d4d4d4">    {</span></span>
<span class="line">        <span style="color: #9cdcfe">$im</span><span style="color: #d4d4d4"> = </span><span style="color: #569cd6">self</span><span style="color: #d4d4d4">::</span><span style="color: #dcdcaa">loadJpeg</span><span style="color: #d4d4d4">(</span><span style="color: #9cdcfe">$src</span><span style="color: #d4d4d4">);</span></span>
<span class="line">        <span style="color: #9cdcfe">$w</span><span style="color: #d4d4d4"> = </span><span style="color: #dcdcaa">imagesx</span><span style="color: #d4d4d4">(</span><span style="color: #9cdcfe">$im</span><span style="color: #d4d4d4">);</span></span>
<span class="line">        <span style="color: #9cdcfe">$h</span><span style="color: #d4d4d4"> = </span><span style="color: #dcdcaa">imagesy</span><span style="color: #d4d4d4">(</span><span style="color: #9cdcfe">$im</span><span style="color: #d4d4d4">);</span></span>

<span class="line">        <span style="color: #c586c0">if</span><span style="color: #d4d4d4"> (</span><span style="color: #9cdcfe">$w</span><span style="color: #d4d4d4"> &lt; </span><span style="color: #569cd6">self</span><span style="color: #d4d4d4">::MIN_WIDTH || </span><span style="color: #9cdcfe">$h</span><span style="color: #d4d4d4"> &lt; </span><span style="color: #569cd6">self</span><span style="color: #d4d4d4">::MIN_HEIGHT) {</span></span>
<span class="line">            <span style="color: #dcdcaa">imagedestroy</span><span style="color: #d4d4d4">(</span><span style="color: #9cdcfe">$im</span><span style="color: #d4d4d4">);</span></span>
<span class="line">            <span style="color: #c586c0">throw</span> <span style="color: #569cd6">new</span> <span style="color: #4ec9b0">RuntimeException</span><span style="color: #d4d4d4">(</span><span style="color: #ce9178">"Image is too small (&lt;200x200). It may not contain a robust watermark."</span><span style="color: #d4d4d4">);</span></span>
<span class="line"><span style="color: #d4d4d4">        }</span></span>

<span class="line">        <span style="color: #6a9955">// Convert to Y</span></span>
<span class="line">        <span style="color: #9cdcfe">$Y</span><span style="color: #d4d4d4"> = </span><span style="color: #569cd6">self</span><span style="color: #d4d4d4">::</span><span style="color: #dcdcaa">rgbToY</span><span style="color: #d4d4d4">(</span><span style="color: #9cdcfe">$im</span><span style="color: #d4d4d4">);</span></span>

<span class="line">        <span style="color: #6a9955">// Apply DCT on 8x8 blocks</span></span>
<span class="line">        <span style="color: #9cdcfe">$blocks</span><span style="color: #d4d4d4"> = </span><span style="color: #569cd6">self</span><span style="color: #d4d4d4">::</span><span style="color: #dcdcaa">forwardBlocks</span><span style="color: #d4d4d4">(</span><span style="color: #9cdcfe">$Y</span><span style="color: #d4d4d4">, </span><span style="color: #9cdcfe">$w</span><span style="color: #d4d4d4">, </span><span style="color: #9cdcfe">$h</span><span style="color: #d4d4d4">);</span></span>

<span class="line">        <span style="color: #6a9955">// Extract the message from the DCT blocks</span></span>
<span class="line">        <span style="color: #9cdcfe">$msg</span><span style="color: #d4d4d4"> = </span><span style="color: #4ec9b0">Watermarker</span><span style="color: #d4d4d4">::</span><span style="color: #dcdcaa">extract</span><span style="color: #d4d4d4">(</span><span style="color: #9cdcfe">$blocks</span><span style="color: #d4d4d4">);</span></span>

<span class="line">        <span style="color: #dcdcaa">imagedestroy</span><span style="color: #d4d4d4">(</span><span style="color: #9cdcfe">$im</span><span style="color: #d4d4d4">);</span></span>
<span class="line">        <span style="color: #c586c0">return</span> <span style="color: #9cdcfe">$msg</span><span style="color: #d4d4d4">;</span></span>
<span class="line"><span style="color: #d4d4d4">    }</span></span>

<span class="line">    <span style="color: #6a9955">/* -------------------------------------------------------------------------</span></span>
<span class="line"><span style="color: #6a9955">       INTERNAL METHODS</span></span>
<span class="line"><span style="color: #6a9955">    -------------------------------------------------------------------------- */</span></span>

<span class="line">    <span style="color: #6a9955">/**</span></span>
<span class="line"><span style="color: #6a9955">     * Loads a JPEG image from disk or throws an exception if invalid.</span></span>
<span class="line"><span style="color: #6a9955">     */</span></span>
<span class="line">    <span style="color: #569cd6">public</span> <span style="color: #569cd6">static</span> <span style="color: #569cd6">function</span> <span style="color: #dcdcaa">loadJpeg</span><span style="color: #d4d4d4">(</span><span style="color: #569cd6">string</span> <span style="color: #9cdcfe">$path</span><span style="color: #d4d4d4">): </span><span style="color: #4ec9b0">GdImage</span></span>
<span class="line"><span style="color: #d4d4d4">    {</span></span>
<span class="line">        <span style="color: #c586c0">if</span><span style="color: #d4d4d4"> (!</span><span style="color: #dcdcaa">is_file</span><span style="color: #d4d4d4">(</span><span style="color: #9cdcfe">$path</span><span style="color: #d4d4d4">)) {</span></span>
<span class="line">            <span style="color: #c586c0">throw</span> <span style="color: #569cd6">new</span> <span style="color: #4ec9b0">RuntimeException</span><span style="color: #d4d4d4">(</span><span style="color: #ce9178">"File not found: </span><span style="color: #9cdcfe">$path</span><span style="color: #ce9178">"</span><span style="color: #d4d4d4">);</span></span>
<span class="line"><span style="color: #d4d4d4">        }</span></span>
<span class="line">        <span style="color: #9cdcfe">$im</span><span style="color: #d4d4d4"> = @</span><span style="color: #dcdcaa">imagecreatefromjpeg</span><span style="color: #d4d4d4">(</span><span style="color: #9cdcfe">$path</span><span style="color: #d4d4d4">);</span></span>
<span class="line">        <span style="color: #c586c0">if</span><span style="color: #d4d4d4"> (!</span><span style="color: #9cdcfe">$im</span><span style="color: #d4d4d4">) {</span></span>
<span class="line">            <span style="color: #c586c0">throw</span> <span style="color: #569cd6">new</span> <span style="color: #4ec9b0">RuntimeException</span><span style="color: #d4d4d4">(</span><span style="color: #ce9178">"Invalid JPEG: </span><span style="color: #9cdcfe">$path</span><span style="color: #ce9178">"</span><span style="color: #d4d4d4">);</span></span>
<span class="line"><span style="color: #d4d4d4">        }</span></span>

<span class="line">        <span style="color: #c586c0">return</span> <span style="color: #9cdcfe">$im</span><span style="color: #d4d4d4">;</span></span>
<span class="line"><span style="color: #d4d4d4">    }</span></span>

<span class="line">    <span style="color: #6a9955">/**</span></span>
<span class="line"><span style="color: #6a9955">     * Converts an RGB image to a 2D Y (luminance) matrix.</span></span>
<span class="line"><span style="color: #6a9955">     */</span></span>
<span class="line">    <span style="color: #569cd6">public</span> <span style="color: #569cd6">static</span> <span style="color: #569cd6">function</span> <span style="color: #dcdcaa">rgbToY</span><span style="color: #d4d4d4">(</span><span style="color: #4ec9b0">GdImage</span> <span style="color: #9cdcfe">$im</span><span style="color: #d4d4d4">): </span><span style="color: #569cd6">array</span></span>
<span class="line"><span style="color: #d4d4d4">    {</span></span>
<span class="line">        <span style="color: #9cdcfe">$w</span><span style="color: #d4d4d4"> = </span><span style="color: #dcdcaa">imagesx</span><span style="color: #d4d4d4">(</span><span style="color: #9cdcfe">$im</span><span style="color: #d4d4d4">);</span></span>
<span class="line">        <span style="color: #9cdcfe">$h</span><span style="color: #d4d4d4"> = </span><span style="color: #dcdcaa">imagesy</span><span style="color: #d4d4d4">(</span><span style="color: #9cdcfe">$im</span><span style="color: #d4d4d4">);</span></span>
<span class="line">        <span style="color: #9cdcfe">$Y</span><span style="color: #d4d4d4"> = </span><span style="color: #dcdcaa">array_fill</span><span style="color: #d4d4d4">(</span><span style="color: #b5cea8">0</span><span style="color: #d4d4d4">, </span><span style="color: #9cdcfe">$h</span><span style="color: #d4d4d4">, </span><span style="color: #dcdcaa">array_fill</span><span style="color: #d4d4d4">(</span><span style="color: #b5cea8">0</span><span style="color: #d4d4d4">, </span><span style="color: #9cdcfe">$w</span><span style="color: #d4d4d4">, </span><span style="color: #b5cea8">0</span><span style="color: #d4d4d4">));</span></span>

<span class="line">        <span style="color: #c586c0">for</span><span style="color: #d4d4d4"> (</span><span style="color: #9cdcfe">$y</span><span style="color: #d4d4d4"> = </span><span style="color: #b5cea8">0</span><span style="color: #d4d4d4">; </span><span style="color: #9cdcfe">$y</span><span style="color: #d4d4d4"> &lt; </span><span style="color: #9cdcfe">$h</span><span style="color: #d4d4d4">; </span><span style="color: #9cdcfe">$y</span><span style="color: #d4d4d4">++) {</span></span>
<span class="line">            <span style="color: #c586c0">for</span><span style="color: #d4d4d4"> (</span><span style="color: #9cdcfe">$x</span><span style="color: #d4d4d4"> = </span><span style="color: #b5cea8">0</span><span style="color: #d4d4d4">; </span><span style="color: #9cdcfe">$x</span><span style="color: #d4d4d4"> &lt; </span><span style="color: #9cdcfe">$w</span><span style="color: #d4d4d4">; </span><span style="color: #9cdcfe">$x</span><span style="color: #d4d4d4">++) {</span></span>
<span class="line">                <span style="color: #9cdcfe">$rgb</span><span style="color: #d4d4d4"> = </span><span style="color: #dcdcaa">imagecolorat</span><span style="color: #d4d4d4">(</span><span style="color: #9cdcfe">$im</span><span style="color: #d4d4d4">, </span><span style="color: #9cdcfe">$x</span><span style="color: #d4d4d4">, </span><span style="color: #9cdcfe">$y</span><span style="color: #d4d4d4">);</span></span>
<span class="line">                <span style="color: #9cdcfe">$r</span><span style="color: #d4d4d4"> = (</span><span style="color: #9cdcfe">$rgb</span><span style="color: #d4d4d4"> &gt;&gt; </span><span style="color: #b5cea8">16</span><span style="color: #d4d4d4">) &amp; </span><span style="color: #b5cea8">0xFF</span><span style="color: #d4d4d4">;</span></span>
<span class="line">                <span style="color: #9cdcfe">$g</span><span style="color: #d4d4d4"> = (</span><span style="color: #9cdcfe">$rgb</span><span style="color: #d4d4d4"> &gt;&gt; </span><span style="color: #b5cea8">8</span><span style="color: #d4d4d4">) &amp; </span><span style="color: #b5cea8">0xFF</span><span style="color: #d4d4d4">;</span></span>
<span class="line">                <span style="color: #9cdcfe">$b</span><span style="color: #d4d4d4"> = </span><span style="color: #9cdcfe">$rgb</span><span style="color: #d4d4d4"> &amp; </span><span style="color: #b5cea8">0xFF</span><span style="color: #d4d4d4">;</span></span>
<span class="line">                <span style="color: #6a9955">// ITU-R BT.601 luma formula</span></span>
<span class="line">                <span style="color: #9cdcfe">$luma</span><span style="color: #d4d4d4"> = (</span><span style="color: #569cd6">int</span><span style="color: #d4d4d4">) </span><span style="color: #dcdcaa">round</span><span style="color: #d4d4d4">(</span><span style="color: #b5cea8">0.299</span><span style="color: #d4d4d4"> * </span><span style="color: #9cdcfe">$r</span><span style="color: #d4d4d4"> + </span><span style="color: #b5cea8">0.587</span><span style="color: #d4d4d4"> * </span><span style="color: #9cdcfe">$g</span><span style="color: #d4d4d4"> + </span><span style="color: #b5cea8">0.114</span><span style="color: #d4d4d4"> * </span><span style="color: #9cdcfe">$b</span><span style="color: #d4d4d4">);</span></span>
<span class="line">                <span style="color: #9cdcfe">$Y</span><span style="color: #d4d4d4">[</span><span style="color: #9cdcfe">$y</span><span style="color: #d4d4d4">][</span><span style="color: #9cdcfe">$x</span><span style="color: #d4d4d4">] = </span><span style="color: #dcdcaa">max</span><span style="color: #d4d4d4">(</span><span style="color: #b5cea8">0</span><span style="color: #d4d4d4">, </span><span style="color: #dcdcaa">min</span><span style="color: #d4d4d4">(</span><span style="color: #b5cea8">255</span><span style="color: #d4d4d4">, </span><span style="color: #9cdcfe">$luma</span><span style="color: #d4d4d4">));</span></span>
<span class="line"><span style="color: #d4d4d4">            }</span></span>
<span class="line"><span style="color: #d4d4d4">        }</span></span>

<span class="line">        <span style="color: #c586c0">return</span> <span style="color: #9cdcfe">$Y</span><span style="color: #d4d4d4">;</span></span>
<span class="line"><span style="color: #d4d4d4">    }</span></span>

<span class="line">    <span style="color: #6a9955">/**</span></span>
<span class="line"><span style="color: #6a9955">     * Splits the Y matrix into 8x8 blocks and applies forward DCT.</span></span>
<span class="line"><span style="color: #6a9955">     */</span></span>
<span class="line">    <span style="color: #569cd6">public</span> <span style="color: #569cd6">static</span> <span style="color: #569cd6">function</span> <span style="color: #dcdcaa">forwardBlocks</span><span style="color: #d4d4d4">(</span><span style="color: #569cd6">array</span> <span style="color: #9cdcfe">$Y</span><span style="color: #d4d4d4">, </span><span style="color: #569cd6">int</span> <span style="color: #9cdcfe">$w</span><span style="color: #d4d4d4">, </span><span style="color: #569cd6">int</span> <span style="color: #9cdcfe">$h</span><span style="color: #d4d4d4">): </span><span style="color: #569cd6">array</span></span>
<span class="line"><span style="color: #d4d4d4">    {</span></span>
<span class="line">        <span style="color: #9cdcfe">$blocks</span><span style="color: #d4d4d4"> = [];</span></span>
<span class="line">        <span style="color: #c586c0">for</span><span style="color: #d4d4d4"> (</span><span style="color: #9cdcfe">$by</span><span style="color: #d4d4d4"> = </span><span style="color: #b5cea8">0</span><span style="color: #d4d4d4">; </span><span style="color: #9cdcfe">$by</span><span style="color: #d4d4d4"> &lt; </span><span style="color: #9cdcfe">$h</span><span style="color: #d4d4d4">; </span><span style="color: #9cdcfe">$by</span><span style="color: #d4d4d4"> += </span><span style="color: #569cd6">self</span><span style="color: #d4d4d4">::BLOCK_SIZE) {</span></span>
<span class="line">            <span style="color: #c586c0">for</span><span style="color: #d4d4d4"> (</span><span style="color: #9cdcfe">$bx</span><span style="color: #d4d4d4"> = </span><span style="color: #b5cea8">0</span><span style="color: #d4d4d4">; </span><span style="color: #9cdcfe">$bx</span><span style="color: #d4d4d4"> &lt; </span><span style="color: #9cdcfe">$w</span><span style="color: #d4d4d4">; </span><span style="color: #9cdcfe">$bx</span><span style="color: #d4d4d4"> += </span><span style="color: #569cd6">self</span><span style="color: #d4d4d4">::BLOCK_SIZE) {</span></span>
<span class="line">                <span style="color: #9cdcfe">$block</span><span style="color: #d4d4d4"> = [];</span></span>
<span class="line">                <span style="color: #c586c0">for</span><span style="color: #d4d4d4"> (</span><span style="color: #9cdcfe">$i</span><span style="color: #d4d4d4"> = </span><span style="color: #b5cea8">0</span><span style="color: #d4d4d4">; </span><span style="color: #9cdcfe">$i</span><span style="color: #d4d4d4"> &lt; </span><span style="color: #569cd6">self</span><span style="color: #d4d4d4">::BLOCK_SIZE; </span><span style="color: #9cdcfe">$i</span><span style="color: #d4d4d4">++) {</span></span>
<span class="line">                    <span style="color: #9cdcfe">$row</span><span style="color: #d4d4d4"> = [];</span></span>
<span class="line">                    <span style="color: #9cdcfe">$srcY</span><span style="color: #d4d4d4"> = </span><span style="color: #dcdcaa">min</span><span style="color: #d4d4d4">(</span><span style="color: #9cdcfe">$by</span><span style="color: #d4d4d4"> + </span><span style="color: #9cdcfe">$i</span><span style="color: #d4d4d4">, </span><span style="color: #9cdcfe">$h</span><span style="color: #d4d4d4"> - </span><span style="color: #b5cea8">1</span><span style="color: #d4d4d4">);</span></span>
<span class="line">                    <span style="color: #c586c0">for</span><span style="color: #d4d4d4"> (</span><span style="color: #9cdcfe">$j</span><span style="color: #d4d4d4"> = </span><span style="color: #b5cea8">0</span><span style="color: #d4d4d4">; </span><span style="color: #9cdcfe">$j</span><span style="color: #d4d4d4"> &lt; </span><span style="color: #569cd6">self</span><span style="color: #d4d4d4">::BLOCK_SIZE; </span><span style="color: #9cdcfe">$j</span><span style="color: #d4d4d4">++) {</span></span>
<span class="line">                        <span style="color: #9cdcfe">$srcX</span><span style="color: #d4d4d4"> = </span><span style="color: #dcdcaa">min</span><span style="color: #d4d4d4">(</span><span style="color: #9cdcfe">$bx</span><span style="color: #d4d4d4"> + </span><span style="color: #9cdcfe">$j</span><span style="color: #d4d4d4">, </span><span style="color: #9cdcfe">$w</span><span style="color: #d4d4d4"> - </span><span style="color: #b5cea8">1</span><span style="color: #d4d4d4">);</span></span>
<span class="line">                        <span style="color: #9cdcfe">$row</span><span style="color: #d4d4d4">[] = </span><span style="color: #9cdcfe">$Y</span><span style="color: #d4d4d4">[</span><span style="color: #9cdcfe">$srcY</span><span style="color: #d4d4d4">][</span><span style="color: #9cdcfe">$srcX</span><span style="color: #d4d4d4">];</span></span>
<span class="line"><span style="color: #d4d4d4">                    }</span></span>
<span class="line">                    <span style="color: #9cdcfe">$block</span><span style="color: #d4d4d4">[] = </span><span style="color: #9cdcfe">$row</span><span style="color: #d4d4d4">;</span></span>
<span class="line"><span style="color: #d4d4d4">                }</span></span>
<span class="line">                <span style="color: #9cdcfe">$blocks</span><span style="color: #d4d4d4">[] = </span><span style="color: #4ec9b0">Dct</span><span style="color: #d4d4d4">::</span><span style="color: #dcdcaa">forward</span><span style="color: #d4d4d4">(</span><span style="color: #9cdcfe">$block</span><span style="color: #d4d4d4">);</span></span>
<span class="line"><span style="color: #d4d4d4">            }</span></span>
<span class="line"><span style="color: #d4d4d4">        }</span></span>
<span class="line">        <span style="color: #c586c0">return</span> <span style="color: #9cdcfe">$blocks</span><span style="color: #d4d4d4">;</span></span>
<span class="line"><span style="color: #d4d4d4">    }</span></span>

<span class="line">    <span style="color: #6a9955">/**</span></span>
<span class="line"><span style="color: #6a9955">     * Applies inverse DCT to each 8x8 block and rebuilds the Y matrix.</span></span>
<span class="line"><span style="color: #6a9955">     */</span></span>
<span class="line">    <span style="color: #569cd6">private</span> <span style="color: #569cd6">static</span> <span style="color: #569cd6">function</span> <span style="color: #dcdcaa">inverseBlocks</span><span style="color: #d4d4d4">(</span><span style="color: #569cd6">array</span> <span style="color: #9cdcfe">$blocks</span><span style="color: #d4d4d4">, </span><span style="color: #569cd6">int</span> <span style="color: #9cdcfe">$w</span><span style="color: #d4d4d4">, </span><span style="color: #569cd6">int</span> <span style="color: #9cdcfe">$h</span><span style="color: #d4d4d4">): </span><span style="color: #569cd6">array</span></span>
<span class="line"><span style="color: #d4d4d4">    {</span></span>
<span class="line">        <span style="color: #9cdcfe">$Y</span><span style="color: #d4d4d4"> = </span><span style="color: #dcdcaa">array_fill</span><span style="color: #d4d4d4">(</span><span style="color: #b5cea8">0</span><span style="color: #d4d4d4">, </span><span style="color: #9cdcfe">$h</span><span style="color: #d4d4d4">, </span><span style="color: #dcdcaa">array_fill</span><span style="color: #d4d4d4">(</span><span style="color: #b5cea8">0</span><span style="color: #d4d4d4">, </span><span style="color: #9cdcfe">$w</span><span style="color: #d4d4d4">, </span><span style="color: #b5cea8">0</span><span style="color: #d4d4d4">));</span></span>
<span class="line">        <span style="color: #9cdcfe">$idx</span><span style="color: #d4d4d4"> = </span><span style="color: #b5cea8">0</span><span style="color: #d4d4d4">;</span></span>

<span class="line">        <span style="color: #c586c0">for</span><span style="color: #d4d4d4"> (</span><span style="color: #9cdcfe">$by</span><span style="color: #d4d4d4"> = </span><span style="color: #b5cea8">0</span><span style="color: #d4d4d4">; </span><span style="color: #9cdcfe">$by</span><span style="color: #d4d4d4"> &lt; </span><span style="color: #9cdcfe">$h</span><span style="color: #d4d4d4">; </span><span style="color: #9cdcfe">$by</span><span style="color: #d4d4d4"> += </span><span style="color: #569cd6">self</span><span style="color: #d4d4d4">::BLOCK_SIZE) {</span></span>
<span class="line">            <span style="color: #c586c0">for</span><span style="color: #d4d4d4"> (</span><span style="color: #9cdcfe">$bx</span><span style="color: #d4d4d4"> = </span><span style="color: #b5cea8">0</span><span style="color: #d4d4d4">; </span><span style="color: #9cdcfe">$bx</span><span style="color: #d4d4d4"> &lt; </span><span style="color: #9cdcfe">$w</span><span style="color: #d4d4d4">; </span><span style="color: #9cdcfe">$bx</span><span style="color: #d4d4d4"> += </span><span style="color: #569cd6">self</span><span style="color: #d4d4d4">::BLOCK_SIZE) {</span></span>
<span class="line">                <span style="color: #9cdcfe">$coeffBlock</span><span style="color: #d4d4d4"> = </span><span style="color: #9cdcfe">$blocks</span><span style="color: #d4d4d4">[</span><span style="color: #9cdcfe">$idx</span><span style="color: #d4d4d4">++];</span></span>
<span class="line">                <span style="color: #9cdcfe">$pixBlock</span><span style="color: #d4d4d4"> = </span><span style="color: #4ec9b0">Dct</span><span style="color: #d4d4d4">::</span><span style="color: #dcdcaa">inverse</span><span style="color: #d4d4d4">(</span><span style="color: #9cdcfe">$coeffBlock</span><span style="color: #d4d4d4">);</span></span>

<span class="line">                <span style="color: #c586c0">for</span><span style="color: #d4d4d4"> (</span><span style="color: #9cdcfe">$i</span><span style="color: #d4d4d4"> = </span><span style="color: #b5cea8">0</span><span style="color: #d4d4d4">; </span><span style="color: #9cdcfe">$i</span><span style="color: #d4d4d4"> &lt; </span><span style="color: #569cd6">self</span><span style="color: #d4d4d4">::BLOCK_SIZE; </span><span style="color: #9cdcfe">$i</span><span style="color: #d4d4d4">++) {</span></span>
<span class="line">                    <span style="color: #9cdcfe">$dstY</span><span style="color: #d4d4d4"> = </span><span style="color: #9cdcfe">$by</span><span style="color: #d4d4d4"> + </span><span style="color: #9cdcfe">$i</span><span style="color: #d4d4d4">;</span></span>
<span class="line">                    <span style="color: #c586c0">if</span><span style="color: #d4d4d4"> (</span><span style="color: #9cdcfe">$dstY</span><span style="color: #d4d4d4"> &gt;= </span><span style="color: #9cdcfe">$h</span><span style="color: #d4d4d4">) </span><span style="color: #c586c0">break</span><span style="color: #d4d4d4">;</span></span>
<span class="line">                    <span style="color: #c586c0">for</span><span style="color: #d4d4d4"> (</span><span style="color: #9cdcfe">$j</span><span style="color: #d4d4d4"> = </span><span style="color: #b5cea8">0</span><span style="color: #d4d4d4">; </span><span style="color: #9cdcfe">$j</span><span style="color: #d4d4d4"> &lt; </span><span style="color: #569cd6">self</span><span style="color: #d4d4d4">::BLOCK_SIZE; </span><span style="color: #9cdcfe">$j</span><span style="color: #d4d4d4">++) {</span></span>
<span class="line">                        <span style="color: #9cdcfe">$dstX</span><span style="color: #d4d4d4"> = </span><span style="color: #9cdcfe">$bx</span><span style="color: #d4d4d4"> + </span><span style="color: #9cdcfe">$j</span><span style="color: #d4d4d4">;</span></span>
<span class="line">                        <span style="color: #c586c0">if</span><span style="color: #d4d4d4"> (</span><span style="color: #9cdcfe">$dstX</span><span style="color: #d4d4d4"> &gt;= </span><span style="color: #9cdcfe">$w</span><span style="color: #d4d4d4">) </span><span style="color: #c586c0">break</span><span style="color: #d4d4d4">;</span></span>
<span class="line">                        <span style="color: #9cdcfe">$Y</span><span style="color: #d4d4d4">[</span><span style="color: #9cdcfe">$dstY</span><span style="color: #d4d4d4">][</span><span style="color: #9cdcfe">$dstX</span><span style="color: #d4d4d4">] = </span><span style="color: #9cdcfe">$pixBlock</span><span style="color: #d4d4d4">[</span><span style="color: #9cdcfe">$i</span><span style="color: #d4d4d4">][</span><span style="color: #9cdcfe">$j</span><span style="color: #d4d4d4">];</span></span>
<span class="line"><span style="color: #d4d4d4">                    }</span></span>
<span class="line"><span style="color: #d4d4d4">                }</span></span>
<span class="line"><span style="color: #d4d4d4">            }</span></span>
<span class="line"><span style="color: #d4d4d4">        }</span></span>

<span class="line">        <span style="color: #c586c0">return</span> <span style="color: #9cdcfe">$Y</span><span style="color: #d4d4d4">;</span></span>
<span class="line"><span style="color: #d4d4d4">    }</span></span>

<span class="line">    <span style="color: #6a9955">/**</span></span>
<span class="line"><span style="color: #6a9955">     * Merges the watermarked Y channel with the original CbCr, then saves the final JPEG.</span></span>
<span class="line"><span style="color: #6a9955">     */</span></span>
<span class="line">    <span style="color: #569cd6">private</span> <span style="color: #569cd6">static</span> <span style="color: #569cd6">function</span> <span style="color: #dcdcaa">mergeAndSave</span><span style="color: #d4d4d4">(</span><span style="color: #4ec9b0">GdImage</span> <span style="color: #9cdcfe">$orig</span><span style="color: #d4d4d4">, </span><span style="color: #569cd6">array</span> <span style="color: #9cdcfe">$Ywm</span><span style="color: #d4d4d4">, </span><span style="color: #569cd6">string</span> <span style="color: #9cdcfe">$dest</span><span style="color: #d4d4d4">, </span><span style="color: #569cd6">int</span> <span style="color: #9cdcfe">$quality</span><span style="color: #d4d4d4">): </span><span style="color: #569cd6">void</span></span>
<span class="line"><span style="color: #d4d4d4">    {</span></span>
<span class="line">        <span style="color: #9cdcfe">$w</span><span style="color: #d4d4d4"> = </span><span style="color: #dcdcaa">imagesx</span><span style="color: #d4d4d4">(</span><span style="color: #9cdcfe">$orig</span><span style="color: #d4d4d4">);</span></span>
<span class="line">        <span style="color: #9cdcfe">$h</span><span style="color: #d4d4d4"> = </span><span style="color: #dcdcaa">imagesy</span><span style="color: #d4d4d4">(</span><span style="color: #9cdcfe">$orig</span><span style="color: #d4d4d4">);</span></span>

<span class="line">        <span style="color: #6a9955">// 1) Overwrite the RGB pixels of the GDImage using the new Y</span></span>
<span class="line">        <span style="color: #c586c0">for</span><span style="color: #d4d4d4"> (</span><span style="color: #9cdcfe">$y</span><span style="color: #d4d4d4"> = </span><span style="color: #b5cea8">0</span><span style="color: #d4d4d4">; </span><span style="color: #9cdcfe">$y</span><span style="color: #d4d4d4"> &lt; </span><span style="color: #9cdcfe">$h</span><span style="color: #d4d4d4">; </span><span style="color: #9cdcfe">$y</span><span style="color: #d4d4d4">++) {</span></span>
<span class="line">            <span style="color: #c586c0">for</span><span style="color: #d4d4d4"> (</span><span style="color: #9cdcfe">$x</span><span style="color: #d4d4d4"> = </span><span style="color: #b5cea8">0</span><span style="color: #d4d4d4">; </span><span style="color: #9cdcfe">$x</span><span style="color: #d4d4d4"> &lt; </span><span style="color: #9cdcfe">$w</span><span style="color: #d4d4d4">; </span><span style="color: #9cdcfe">$x</span><span style="color: #d4d4d4">++) {</span></span>
<span class="line">                <span style="color: #9cdcfe">$rgb</span><span style="color: #d4d4d4"> = </span><span style="color: #dcdcaa">imagecolorat</span><span style="color: #d4d4d4">(</span><span style="color: #9cdcfe">$orig</span><span style="color: #d4d4d4">, </span><span style="color: #9cdcfe">$x</span><span style="color: #d4d4d4">, </span><span style="color: #9cdcfe">$y</span><span style="color: #d4d4d4">);</span></span>
<span class="line">                <span style="color: #9cdcfe">$r</span><span style="color: #d4d4d4"> = (</span><span style="color: #9cdcfe">$rgb</span><span style="color: #d4d4d4"> &gt;&gt; </span><span style="color: #b5cea8">16</span><span style="color: #d4d4d4">) &amp; </span><span style="color: #b5cea8">0xFF</span><span style="color: #d4d4d4">;</span></span>
<span class="line">                <span style="color: #9cdcfe">$g</span><span style="color: #d4d4d4"> = (</span><span style="color: #9cdcfe">$rgb</span><span style="color: #d4d4d4"> &gt;&gt; </span><span style="color: #b5cea8">8</span><span style="color: #d4d4d4">) &amp; </span><span style="color: #b5cea8">0xFF</span><span style="color: #d4d4d4">;</span></span>
<span class="line">                <span style="color: #9cdcfe">$b</span><span style="color: #d4d4d4"> = </span><span style="color: #9cdcfe">$rgb</span><span style="color: #d4d4d4"> &amp; </span><span style="color: #b5cea8">0xFF</span><span style="color: #d4d4d4">;</span></span>

<span class="line">                <span style="color: #9cdcfe">$cb</span><span style="color: #d4d4d4"> = -</span><span style="color: #b5cea8">0.169</span><span style="color: #d4d4d4"> * </span><span style="color: #9cdcfe">$r</span><span style="color: #d4d4d4"> - </span><span style="color: #b5cea8">0.331</span><span style="color: #d4d4d4"> * </span><span style="color: #9cdcfe">$g</span><span style="color: #d4d4d4"> + </span><span style="color: #b5cea8">0.5</span><span style="color: #d4d4d4"> * </span><span style="color: #9cdcfe">$b</span><span style="color: #d4d4d4"> + </span><span style="color: #b5cea8">128</span><span style="color: #d4d4d4">;</span></span>
<span class="line">                <span style="color: #9cdcfe">$cr</span><span style="color: #d4d4d4"> = </span><span style="color: #b5cea8">0.5</span><span style="color: #d4d4d4"> * </span><span style="color: #9cdcfe">$r</span><span style="color: #d4d4d4"> - </span><span style="color: #b5cea8">0.419</span><span style="color: #d4d4d4"> * </span><span style="color: #9cdcfe">$g</span><span style="color: #d4d4d4"> - </span><span style="color: #b5cea8">0.081</span><span style="color: #d4d4d4"> * </span><span style="color: #9cdcfe">$b</span><span style="color: #d4d4d4"> + </span><span style="color: #b5cea8">128</span><span style="color: #d4d4d4">;</span></span>

<span class="line">                <span style="color: #9cdcfe">$Yval</span><span style="color: #d4d4d4"> = </span><span style="color: #9cdcfe">$Ywm</span><span style="color: #d4d4d4">[</span><span style="color: #9cdcfe">$y</span><span style="color: #d4d4d4">][</span><span style="color: #9cdcfe">$x</span><span style="color: #d4d4d4">];</span></span>

<span class="line">                <span style="color: #9cdcfe">$R</span><span style="color: #d4d4d4"> = </span><span style="color: #9cdcfe">$Yval</span><span style="color: #d4d4d4"> + </span><span style="color: #b5cea8">1.402</span><span style="color: #d4d4d4"> * (</span><span style="color: #9cdcfe">$cr</span><span style="color: #d4d4d4"> - </span><span style="color: #b5cea8">128</span><span style="color: #d4d4d4">);</span></span>
<span class="line">                <span style="color: #9cdcfe">$G</span><span style="color: #d4d4d4"> = </span><span style="color: #9cdcfe">$Yval</span><span style="color: #d4d4d4"> - </span><span style="color: #b5cea8">0.344136</span><span style="color: #d4d4d4"> * (</span><span style="color: #9cdcfe">$cb</span><span style="color: #d4d4d4"> - </span><span style="color: #b5cea8">128</span><span style="color: #d4d4d4">) - </span><span style="color: #b5cea8">0.714136</span><span style="color: #d4d4d4"> * (</span><span style="color: #9cdcfe">$cr</span><span style="color: #d4d4d4"> - </span><span style="color: #b5cea8">128</span><span style="color: #d4d4d4">);</span></span>
<span class="line">                <span style="color: #9cdcfe">$B</span><span style="color: #d4d4d4"> = </span><span style="color: #9cdcfe">$Yval</span><span style="color: #d4d4d4"> + </span><span style="color: #b5cea8">1.772</span><span style="color: #d4d4d4"> * (</span><span style="color: #9cdcfe">$cb</span><span style="color: #d4d4d4"> - </span><span style="color: #b5cea8">128</span><span style="color: #d4d4d4">);</span></span>

<span class="line">                <span style="color: #9cdcfe">$R</span><span style="color: #d4d4d4"> = </span><span style="color: #dcdcaa">max</span><span style="color: #d4d4d4">(</span><span style="color: #b5cea8">0</span><span style="color: #d4d4d4">, </span><span style="color: #dcdcaa">min</span><span style="color: #d4d4d4">(</span><span style="color: #b5cea8">255</span><span style="color: #d4d4d4">, (</span><span style="color: #569cd6">int</span><span style="color: #d4d4d4">) </span><span style="color: #dcdcaa">round</span><span style="color: #d4d4d4">(</span><span style="color: #9cdcfe">$R</span><span style="color: #d4d4d4">)));</span></span>
<span class="line">                <span style="color: #9cdcfe">$G</span><span style="color: #d4d4d4"> = </span><span style="color: #dcdcaa">max</span><span style="color: #d4d4d4">(</span><span style="color: #b5cea8">0</span><span style="color: #d4d4d4">, </span><span style="color: #dcdcaa">min</span><span style="color: #d4d4d4">(</span><span style="color: #b5cea8">255</span><span style="color: #d4d4d4">, (</span><span style="color: #569cd6">int</span><span style="color: #d4d4d4">) </span><span style="color: #dcdcaa">round</span><span style="color: #d4d4d4">(</span><span style="color: #9cdcfe">$G</span><span style="color: #d4d4d4">)));</span></span>
<span class="line">                <span style="color: #9cdcfe">$B</span><span style="color: #d4d4d4"> = </span><span style="color: #dcdcaa">max</span><span style="color: #d4d4d4">(</span><span style="color: #b5cea8">0</span><span style="color: #d4d4d4">, </span><span style="color: #dcdcaa">min</span><span style="color: #d4d4d4">(</span><span style="color: #b5cea8">255</span><span style="color: #d4d4d4">, (</span><span style="color: #569cd6">int</span><span style="color: #d4d4d4">) </span><span style="color: #dcdcaa">round</span><span style="color: #d4d4d4">(</span><span style="color: #9cdcfe">$B</span><span style="color: #d4d4d4">)));</span></span>

<span class="line">                <span style="color: #9cdcfe">$color</span><span style="color: #d4d4d4"> = </span><span style="color: #dcdcaa">imagecolorallocate</span><span style="color: #d4d4d4">(</span><span style="color: #9cdcfe">$orig</span><span style="color: #d4d4d4">, </span><span style="color: #9cdcfe">$R</span><span style="color: #d4d4d4">, </span><span style="color: #9cdcfe">$G</span><span style="color: #d4d4d4">, </span><span style="color: #9cdcfe">$B</span><span style="color: #d4d4d4">);</span></span>
<span class="line">                <span style="color: #dcdcaa">imagesetpixel</span><span style="color: #d4d4d4">(</span><span style="color: #9cdcfe">$orig</span><span style="color: #d4d4d4">, </span><span style="color: #9cdcfe">$x</span><span style="color: #d4d4d4">, </span><span style="color: #9cdcfe">$y</span><span style="color: #d4d4d4">, </span><span style="color: #9cdcfe">$color</span><span style="color: #d4d4d4">);</span></span>
<span class="line"><span style="color: #d4d4d4">            }</span></span>
<span class="line"><span style="color: #d4d4d4">        }</span></span>

<span class="line">        <span style="color: #6a9955">// 2) Convert GDImage to a PNG blob in memory (lossless)</span></span>
<span class="line">        <span style="color: #dcdcaa">ob_start</span><span style="color: #d4d4d4">();</span></span>
<span class="line">        <span style="color: #dcdcaa">imagepng</span><span style="color: #d4d4d4">(</span><span style="color: #9cdcfe">$orig</span><span style="color: #d4d4d4">);</span></span>
<span class="line">        <span style="color: #9cdcfe">$pngData</span><span style="color: #d4d4d4"> = </span><span style="color: #dcdcaa">ob_get_clean</span><span style="color: #d4d4d4">();</span></span>

<span class="line">        <span style="color: #6a9955">// 3) Create an Imagick object from the PNG blob</span></span>
<span class="line">        <span style="color: #9cdcfe">$imagick</span><span style="color: #d4d4d4"> = </span><span style="color: #569cd6">new</span> <span style="color: #4ec9b0">Imagick</span><span style="color: #d4d4d4">();</span></span>
<span class="line">        <span style="color: #9cdcfe">$imagick</span><span style="color: #d4d4d4">-&gt;</span><span style="color: #dcdcaa">readImageBlob</span><span style="color: #d4d4d4">(</span><span style="color: #9cdcfe">$pngData</span><span style="color: #d4d4d4">);</span></span>

<span class="line">        <span style="color: #6a9955">// 4) Set desired JPEG parameters</span></span>
<span class="line">        <span style="color: #9cdcfe">$imagick</span><span style="color: #d4d4d4">-&gt;</span><span style="color: #dcdcaa">setOption</span><span style="color: #d4d4d4">(</span><span style="color: #ce9178">'jpeg:sampling-factor'</span><span style="color: #d4d4d4">, </span><span style="color: #ce9178">'1x1'</span><span style="color: #d4d4d4">); </span><span style="color: #6a9955">// disable chroma subsampling</span></span>
<span class="line">        <span style="color: #9cdcfe">$imagick</span><span style="color: #d4d4d4">-&gt;</span><span style="color: #dcdcaa">setImageCompressionQuality</span><span style="color: #d4d4d4">(</span><span style="color: #9cdcfe">$quality</span><span style="color: #d4d4d4">);</span></span>
<span class="line">        <span style="color: #9cdcfe">$imagick</span><span style="color: #d4d4d4">-&gt;</span><span style="color: #dcdcaa">setImageCompression</span><span style="color: #d4d4d4">(</span><span style="color: #4ec9b0">Imagick</span><span style="color: #d4d4d4">::COMPRESSION_JPEG);</span></span>
<span class="line">        <span style="color: #9cdcfe">$imagick</span><span style="color: #d4d4d4">-&gt;</span><span style="color: #dcdcaa">setImageFormat</span><span style="color: #d4d4d4">(</span><span style="color: #ce9178">'jpeg'</span><span style="color: #d4d4d4">);</span></span>

<span class="line">        <span style="color: #6a9955">// 5) Save the file</span></span>
<span class="line">        <span style="color: #9cdcfe">$imagick</span><span style="color: #d4d4d4">-&gt;</span><span style="color: #dcdcaa">writeImage</span><span style="color: #d4d4d4">(</span><span style="color: #9cdcfe">$dest</span><span style="color: #d4d4d4">);</span></span>

<span class="line">        <span style="color: #6a9955">// 6) Cleanup</span></span>
<span class="line">        <span style="color: #9cdcfe">$imagick</span><span style="color: #d4d4d4">-&gt;</span><span style="color: #dcdcaa">destroy</span><span style="color: #d4d4d4">();</span></span>
<span class="line"><span style="color: #d4d4d4">    }</span></span>

<span class="line">    <span style="color: #6a9955">/**</span></span>
<span class="line"><span style="color: #6a9955">     * Prevents instantiation.</span></span>
<span class="line"><span style="color: #6a9955">     */</span></span>
<span class="line">    <span style="color: #569cd6">private</span> <span style="color: #569cd6">function</span> <span style="color: #dcdcaa">__construct</span><span style="color: #d4d4d4">()</span></span>
<span class="line"><span style="color: #d4d4d4">    {</span></span>
<span class="line"><span style="color: #d4d4d4">    }</span></span>
<span class="line"><span style="color: #d4d4d4">}</span></span></code></pre>
</div>


<p>Quando si invoca il metodo statico embed, il codice apre l’immagine con l’estensione GD e ricava la componente Y di luminanza — l’unica coinvolta nel watermarking — lasciando invariati i canali cromatici Cb e Cr per garantire che la firma resti invisibile all’occhio umano. La matrice Y viene poi suddivisa, riga per riga, in una griglia di blocchi 8×8. Ciascun blocco viene trasformato in frequenza con Dct::forward, così da permettere alla classe Watermarker di incidere i bit del messaggio <strong>forzando il segno</strong> di 8 coefficienti a <strong>bassa frequenza</strong> scelti appositamente.</p>
<p>Terminata l’incisione, ImageIO riconverte ogni blocco in pixel con Dct::inverse, ricostruendo una nuova matrice Y marcata. A questo punto la classe ricalcola i valori RGB combinando la luminanza modificata con le crominanze originali: per ogni pixel applica le formule inverse dello spazio colore secondo lo standard ITU-R BT.601, assicurandosi che i risultati restino nell’intervallo 0–255.</p>
<p>Il bitmap completo viene infine salvato in JPEG alla qualità desiderata, utilizzando Imagick per disattivare il subsampling cromatico e massimizzare la fedeltà. Il risultato è un file visivamente identico all’originale ma contenente, nei suoi coefficienti DCT, una firma testuale invisibile ma resistente.</p>
<p>Il percorso inverso, affidato al metodo extract, compie l’operazione opposta: ricarica l’immagine, isola la luminanza, la suddivide in blocchi, calcola la DCT di ciascuno e passa la sequenza di coefficienti a Watermarker::extract. Questo metodo legge il <strong>segno</strong> dei coefficienti, applica il voto di maggioranza tra le ripetizioni di ciascun bit, e ricostruisce la stringa originaria fino al carattere NUL di terminazione.</p>
<p>Tutta la logica di I/O, apertura dei file, conversione colore e salvataggio JPEG è confinata nella classe ImageIO, mentre Dct e Watermarker restano funzioni matematiche pure. Questa divisione chiara delle responsabilità favorisce la modularità del codice, la testabilità e l’integrazione in qualunque pipeline di elaborazione immagini.</p>
<h2 class="wp-block-heading">Test in CLI</h2>
<h3 class="wp-block-heading">/embed.php</h3>
<p>Inserimento di un watermark in un&#8217;immagine</p>


<div class="wp-block-kevinbatdorf-code-block-pro" style="font-size: .875rem;font-family: Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height: 1.25rem;--cbp-tab-width: 2" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono">
<pre class="shiki dark-plus" style="background-color: #1e1e1e"><code><span class="line"><span style="color: #6a9955">#!/usr/bin/env php</span></span>
<span class="line"><span style="color: #d4d4d4">&lt;?php</span></span>

<span class="line"><span style="color: #6a9955">// Set memory limit to 1GB</span></span>
<span class="line"><span style="color: #dcdcaa">ini_set</span><span style="color: #d4d4d4">(</span><span style="color: #ce9178">'memory_limit'</span><span style="color: #d4d4d4">, </span><span style="color: #ce9178">'1024M'</span><span style="color: #d4d4d4">);</span></span>
<span class="line"><span style="color: #c586c0">require</span> <span style="color: #569cd6">__DIR__</span> <span style="color: #d4d4d4">.</span> <span style="color: #ce9178">'/vendor/autoload.php'</span><span style="color: #d4d4d4">;</span></span>

<span class="line"><span style="color: #569cd6">use</span><span style="color: #d4d4d4"> RenorWatermark</span><span style="color: #4ec9b0">ImageIO</span><span style="color: #d4d4d4">;</span></span>

<span class="line"><span style="color: #6a9955">/**</span></span>
<span class="line"><span style="color: #6a9955"> * This command-line script embeds a watermark (up to 10 characters)</span></span>
<span class="line"><span style="color: #6a9955"> * into a JPEG and saves the result. By default, it uses quality=90.</span></span>
<span class="line"><span style="color: #6a9955"> *</span></span>
<span class="line"><span style="color: #6a9955"> * Example usage:</span></span>
<span class="line"><span style="color: #6a9955"> *   php embed.php --src=original.jpg --out=watermarked.jpg --msg="HELLO" --q=95</span></span>
<span class="line"><span style="color: #6a9955"> *</span></span>
<span class="line"><span style="color: #6a9955"> * Or simply:</span></span>
<span class="line"><span style="color: #6a9955"> *   php embed.php --src=original.jpg --out=watermarked.jpg</span></span>
<span class="line"><span style="color: #6a9955"> *   (defaults to msg="DEFAULT" and quality=90)</span></span>
<span class="line"><span style="color: #6a9955"> */</span></span>

<span class="line"><span style="color: #9cdcfe">$options</span><span style="color: #d4d4d4"> = </span><span style="color: #dcdcaa">getopt</span><span style="color: #d4d4d4">(</span><span style="color: #ce9178">''</span><span style="color: #d4d4d4">, [</span><span style="color: #ce9178">'src:'</span><span style="color: #d4d4d4">, </span><span style="color: #ce9178">'out:'</span><span style="color: #d4d4d4">, </span><span style="color: #ce9178">'msg::'</span><span style="color: #d4d4d4">, </span><span style="color: #ce9178">'q::'</span><span style="color: #d4d4d4">]);</span></span>
<span class="line"><span style="color: #9cdcfe">$src</span><span style="color: #d4d4d4"> = </span><span style="color: #9cdcfe">$options</span><span style="color: #d4d4d4">[</span><span style="color: #ce9178">'src'</span><span style="color: #d4d4d4">] ?? </span><span style="color: #569cd6">null</span><span style="color: #d4d4d4">;</span></span>
<span class="line"><span style="color: #9cdcfe">$out</span><span style="color: #d4d4d4"> = </span><span style="color: #9cdcfe">$options</span><span style="color: #d4d4d4">[</span><span style="color: #ce9178">'out'</span><span style="color: #d4d4d4">] ?? </span><span style="color: #569cd6">null</span><span style="color: #d4d4d4">;</span></span>
<span class="line"><span style="color: #9cdcfe">$msg</span><span style="color: #d4d4d4"> = </span><span style="color: #9cdcfe">$options</span><span style="color: #d4d4d4">[</span><span style="color: #ce9178">'msg'</span><span style="color: #d4d4d4">] ?? </span><span style="color: #ce9178">'DEFAULT'</span><span style="color: #d4d4d4">;</span></span>
<span class="line"><span style="color: #9cdcfe">$q</span><span style="color: #d4d4d4">   = </span><span style="color: #dcdcaa">isset</span><span style="color: #d4d4d4">(</span><span style="color: #9cdcfe">$options</span><span style="color: #d4d4d4">[</span><span style="color: #ce9178">'q'</span><span style="color: #d4d4d4">]) ? (</span><span style="color: #569cd6">int</span><span style="color: #d4d4d4">) </span><span style="color: #9cdcfe">$options</span><span style="color: #d4d4d4">[</span><span style="color: #ce9178">'q'</span><span style="color: #d4d4d4">] : </span><span style="color: #b5cea8">90</span><span style="color: #d4d4d4">;</span></span>

<span class="line"><span style="color: #c586c0">if</span><span style="color: #d4d4d4"> (!</span><span style="color: #9cdcfe">$src</span><span style="color: #d4d4d4"> || !</span><span style="color: #9cdcfe">$out</span><span style="color: #d4d4d4">) {</span></span>
<span class="line">    <span style="color: #dcdcaa">fwrite</span><span style="color: #d4d4d4">(STDERR, </span><span style="color: #ce9178">"Usage: embed --src=INPUT.jpg --out=OUTPUT.jpg [--msg=STRING] [--q=90]</span><span style="color: #d7ba7d">n</span><span style="color: #ce9178">"</span><span style="color: #d4d4d4">);</span></span>
<span class="line">    <span style="color: #c586c0">exit</span><span style="color: #d4d4d4">(</span><span style="color: #b5cea8">1</span><span style="color: #d4d4d4">);</span></span>
<span class="line"><span style="color: #d4d4d4">}</span></span>

<span class="line"><span style="color: #c586c0">try</span><span style="color: #d4d4d4"> {</span></span>
<span class="line">    <span style="color: #4ec9b0">ImageIO</span><span style="color: #d4d4d4">::</span><span style="color: #dcdcaa">embed</span><span style="color: #d4d4d4">(</span><span style="color: #9cdcfe">$src</span><span style="color: #d4d4d4">, </span><span style="color: #9cdcfe">$out</span><span style="color: #d4d4d4">, </span><span style="color: #9cdcfe">$msg</span><span style="color: #d4d4d4">, </span><span style="color: #9cdcfe">$q</span><span style="color: #d4d4d4">);</span></span>
<span class="line">    <span style="color: #dcdcaa">echo</span> <span style="color: #ce9178">"Watermark </span><span style="color: #d7ba7d">"</span><span style="color: #9cdcfe">$msg</span><span style="color: #d7ba7d">"</span><span style="color: #ce9178"> embedded successfully into </span><span style="color: #9cdcfe">$out</span><span style="color: #ce9178"> at quality </span><span style="color: #9cdcfe">$q</span><span style="color: #d7ba7d">n</span><span style="color: #ce9178">"</span><span style="color: #d4d4d4">;</span></span>
<span class="line"><span style="color: #d4d4d4">} </span><span style="color: #c586c0">catch</span><span style="color: #d4d4d4"> (</span><span style="color: #4ec9b0">Exception</span> <span style="color: #9cdcfe">$e</span><span style="color: #d4d4d4">) {</span></span>
<span class="line">    <span style="color: #dcdcaa">fwrite</span><span style="color: #d4d4d4">(STDERR, </span><span style="color: #ce9178">"Error: "</span> <span style="color: #d4d4d4">.</span> <span style="color: #9cdcfe">$e</span><span style="color: #d4d4d4">-&gt;</span><span style="color: #dcdcaa">getMessage</span><span style="color: #d4d4d4">() </span><span style="color: #d4d4d4">.</span> <span style="color: #ce9178">"</span><span style="color: #d7ba7d">n</span><span style="color: #ce9178">"</span><span style="color: #d4d4d4">);</span></span>
<span class="line">    <span style="color: #c586c0">exit</span><span style="color: #d4d4d4">(</span><span style="color: #b5cea8">1</span><span style="color: #d4d4d4">);</span></span>
<span class="line"><span style="color: #d4d4d4">}</span></span></code></pre>
</div>


<p>In questo script CLI (embed.php) definiamo, attraverso l’opzione &#8211;msg, il messaggio da imprimere nell’immagine e invochiamo il metodo statico ImageIO::embed() della classe ImageIO. Lo script accetta i seguenti parametri:</p>
<p>&#8211;q (facoltativo): la qualità JPEG per il salvataggio (default: 90).</p>
<p>&#8211;src: il percorso dell’immagine JPEG sorgente (es. original.jpg);</p>
<p>&#8211;out: il percorso del file JPEG di destinazione che conterrà il watermark;</p>
<p>&#8211;msg (facoltativo): il testo ASCII da inserire (max 10 caratteri);</p>


<pre class="wp-block-code"><code>php embed.php --src=original.jpg --out=watermarked.jpg --msg="RENOR" --q=95</code></pre>


<p>ci tornerà:</p>


<pre class="wp-block-code"><code>Watermark "RENOR" embedded successfully into watermarked.jpg at quality 95</code></pre>


<h2 class="wp-block-heading">/extract.php</h2>
<p>Da qui estraiamo il testo del Watermark contenuto nell&#8217;immagine watermarked.jpg appena creata da embed.php</p>


<div class="wp-block-kevinbatdorf-code-block-pro" style="font-size: .875rem;font-family: Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height: 1.25rem;--cbp-tab-width: 2" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono">
<pre class="shiki dark-plus" style="background-color: #1e1e1e"><code><span class="line"><span style="color: #6a9955">#!/usr/bin/env php</span></span>
<span class="line"><span style="color: #d4d4d4">&lt;?php</span></span>

<span class="line"><span style="color: #6a9955">// Set memory limit to 1GB</span></span>
<span class="line"><span style="color: #dcdcaa">ini_set</span><span style="color: #d4d4d4">(</span><span style="color: #ce9178">'memory_limit'</span><span style="color: #d4d4d4">, </span><span style="color: #ce9178">'1024M'</span><span style="color: #d4d4d4">);</span></span>
<span class="line"><span style="color: #c586c0">require</span> <span style="color: #569cd6">__DIR__</span> <span style="color: #d4d4d4">.</span> <span style="color: #ce9178">'/vendor/autoload.php'</span><span style="color: #d4d4d4">;</span></span>

<span class="line"><span style="color: #569cd6">use</span><span style="color: #d4d4d4"> RenorWatermark</span><span style="color: #4ec9b0">ImageIO</span><span style="color: #d4d4d4">;</span></span>

<span class="line"><span style="color: #6a9955">/**</span></span>
<span class="line"><span style="color: #6a9955"> * This command-line script extracts a watermark from a JPEG.</span></span>
<span class="line"><span style="color: #6a9955"> *</span></span>
<span class="line"><span style="color: #6a9955"> * Usage:</span></span>
<span class="line"><span style="color: #6a9955"> *   php extract.php --src=watermarked.jpg</span></span>
<span class="line"><span style="color: #6a9955"> */</span></span>

<span class="line"><span style="color: #9cdcfe">$options</span><span style="color: #d4d4d4"> = </span><span style="color: #dcdcaa">getopt</span><span style="color: #d4d4d4">(</span><span style="color: #ce9178">''</span><span style="color: #d4d4d4">, [</span><span style="color: #ce9178">'src:'</span><span style="color: #d4d4d4">]);</span></span>
<span class="line"><span style="color: #9cdcfe">$src</span><span style="color: #d4d4d4"> = </span><span style="color: #9cdcfe">$options</span><span style="color: #d4d4d4">[</span><span style="color: #ce9178">'src'</span><span style="color: #d4d4d4">] ?? </span><span style="color: #569cd6">null</span><span style="color: #d4d4d4">;</span></span>

<span class="line"><span style="color: #c586c0">if</span><span style="color: #d4d4d4"> (!</span><span style="color: #9cdcfe">$src</span><span style="color: #d4d4d4">) {</span></span>
<span class="line">    <span style="color: #dcdcaa">fwrite</span><span style="color: #d4d4d4">(STDERR, </span><span style="color: #ce9178">"Usage: extract --src=IMAGE.jpg</span><span style="color: #d7ba7d">n</span><span style="color: #ce9178">"</span><span style="color: #d4d4d4">);</span></span>
<span class="line">    <span style="color: #c586c0">exit</span><span style="color: #d4d4d4">(</span><span style="color: #b5cea8">1</span><span style="color: #d4d4d4">);</span></span>
<span class="line"><span style="color: #d4d4d4">}</span></span>

<span class="line"><span style="color: #c586c0">try</span><span style="color: #d4d4d4"> {</span></span>
<span class="line">    <span style="color: #9cdcfe">$msg</span><span style="color: #d4d4d4"> = </span><span style="color: #4ec9b0">ImageIO</span><span style="color: #d4d4d4">::</span><span style="color: #dcdcaa">extract</span><span style="color: #d4d4d4">(</span><span style="color: #9cdcfe">$src</span><span style="color: #d4d4d4">);</span></span>
<span class="line">    <span style="color: #dcdcaa">echo</span> <span style="color: #ce9178">"Recovered message: </span><span style="color: #d7ba7d">"</span><span style="color: #9cdcfe">$msg</span><span style="color: #d7ba7d">"n</span><span style="color: #ce9178">"</span><span style="color: #d4d4d4">;</span></span>
<span class="line"><span style="color: #d4d4d4">} </span><span style="color: #c586c0">catch</span><span style="color: #d4d4d4"> (</span><span style="color: #4ec9b0">Exception</span> <span style="color: #9cdcfe">$e</span><span style="color: #d4d4d4">) {</span></span>
<span class="line">    <span style="color: #dcdcaa">fwrite</span><span style="color: #d4d4d4">(STDERR, </span><span style="color: #ce9178">"Error: "</span> <span style="color: #d4d4d4">.</span> <span style="color: #9cdcfe">$e</span><span style="color: #d4d4d4">-&gt;</span><span style="color: #dcdcaa">getMessage</span><span style="color: #d4d4d4">() </span><span style="color: #d4d4d4">.</span> <span style="color: #ce9178">"</span><span style="color: #d7ba7d">n</span><span style="color: #ce9178">"</span><span style="color: #d4d4d4">);</span></span>
<span class="line">    <span style="color: #c586c0">exit</span><span style="color: #d4d4d4">(</span><span style="color: #b5cea8">1</span><span style="color: #d4d4d4">);</span></span>
<span class="line"><span style="color: #d4d4d4">}</span></span></code></pre>
</div>


<p>Lo script extract.php completa il ciclo di utilizzo del watermark invisibile permettendo l’estrazione del messaggio precedentemente incorporato. Si tratta di un semplice script da linea di comando che, dato un file JPEG marcato, ne legge il contenuto nascosto decodificando il segno di specifici coefficienti DCT modificati. Il messaggio, recuperato in modo robusto anche dopo compressioni JPEG con qualità medio-alta, viene ricostruito tramite voto di maggioranza sui bit ripetuti. Basta eseguire il comando con l’opzione &#8211;src per indicare l’immagine da analizzare, e lo script restituirà a terminale la stringa originariamente incorporata.</p>
<p>Possiamo landiare il comando:</p>


<pre class="wp-block-code"><code>php extract.php --src=watermarked.jpg  </code></pre>


<p>otterremo:</p>


<pre class="wp-block-code"><code>Recovered message: "RENOR"</code></pre>


<p>Vale il caso anche di analizzare le fotografie:</p>


<figure class="wp-block-image size-large"><img decoding="async" src="https://renor.it/wp-content/uploads/2025/05/test-1024x342.webp" alt="" class="wp-image-360" /></figure>


<p>A sinistra l&#8217;immagine originale, a destra quella watermarked.</p>
<p>Possiamo notare che effettivamente, come abbiamo ampiamente descritto non ci sono elementi visibili ad occhi nudo e riconducibili all&#8217;applicazione di un Watermark che resta tuttavia ancora decifrabile utilizzando l&#8217;extract. </p>
<p>Chiaramente il progetto è puramente dimostrativo ed utilizzarlo a livello enterprise o per progetti in produzione richiederebbe ulteriore raffinamento.</p>


<p class="wp-block-paragraph"><strong>[starbox]&nbsp;</strong></p>

<p>L'articolo <a href="https://renor.it/blog/sviluppo-software-programmazione/watermark-invisibile-in-jpeg-con-php-8/">Watermark Invisibile in JPEG con PHP 8</a> proviene da <a href="https://renor.it">RENOR &amp; Partners S.r.l.</a>.</p>
]]></content:encoded>
					
		
		
			</item>
	</channel>
</rss>
