<?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>Software Development &amp; Programming | RENOR &amp; Partners S.r.l.</title>
	<atom:link href="https://renor.it/en/blog/software-development-programming/feed/" rel="self" type="application/rss+xml" />
	<link>https://renor.it/en/blog/software-development-programming/</link>
	<description></description>
	<lastBuildDate>Wed, 04 Nov 2026 13:49:41 +0000</lastBuildDate>
	<language>en-US</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=7.1.4</generator>
	<item>
		<title>IT Consulting and Custom Software for SMEs: The Complete Guide</title>
		<link>https://renor.it/en/blog/software-development-programming/it-consulting-custom-software-development-for-smes/</link>
		
		<dc:creator><![CDATA[Simone Renzi]]></dc:creator>
		<pubDate>Tue, 03 Nov 2026 13:25:45 +0000</pubDate>
				<category><![CDATA[Software Development & Programming]]></category>
		<category><![CDATA[digital transformation]]></category>
		<category><![CDATA[innovation]]></category>
		<category><![CDATA[renor]]></category>
		<category><![CDATA[technology]]></category>
		<guid isPermaLink="false">https://renor.it/blog/software-development-programming/it-consulting-custom-software-development-for-smes/</guid>

					<description><![CDATA[<p>Discover how IT consulting and personalized software development transform Italian SMEs. Custom solutions to grow and innovate your business today.</p>
<p>L'articolo <a href="https://renor.it/en/blog/software-development-programming/it-consulting-custom-software-development-for-smes/">IT Consulting and Custom Software for SMEs: The Complete Guide</a> proviene da <a href="https://renor.it/en/">RENOR &amp; Partners S.r.l.</a>.</p>
]]></description>
										<content:encoded><![CDATA[<h2 class="wp-block-heading">Why Small and Medium Businesses Should Choose Custom-Built Software</h2><p class="wp-block-paragraph">As a company grows, it eventually faces a crossroads: keep forcing its processes to fit a standard software package, or build a tool that adapts to how the business actually works. This isn&#039;t just a technical detail—it&#039;s a choice that impacts every single day on your timeline, budget, and work quality.</p><p class="wp-block-paragraph">Off-the-shelf software is designed to satisfy as many customers as possible. As a result, it comes loaded with countless features you&#039;ll never need, while missing the specific capabilities that define your business. The outcome is a compromise: your organization bends to fit the program instead of the other way around.</p><p class="wp-block-paragraph">The most common limitations of standard software packages are concrete and easy to spot:</p><ul class="wp-block-list"><li>Rigid features that don&#039;t match your real workflow, forcing staff through unnecessary steps or makeshift workarounds</li><li>Data entry duplication across disconnected systems, leading to errors and wasted time</li><li>Recurring license costs for modules you don&#039;t actually use</li><li>Difficulty integrating existing tools or scaling the software as your company evolves</li><li>Lock-in with a vendor who controls when and what gets updated</li></ul><p class="wp-block-paragraph">Custom-built software flips this logic on its head: it starts with your processes and translates them into a tool that mirrors them. Your team finds their own workflows digitized, without having to learn to think like the software. Repetitive tasks automate themselves, data flows without duplicate entry, and the tool grows with your company—adding features only when you truly need them.</p><p class="wp-block-paragraph">That&#039;s where the competitive advantage lies: while competitors adapt to constraints imposed by others, you have a tool that reinforces your unique way of working and makes it faster. It&#039;s an investment that pays off in daily efficiency, not just an expense for expense&#039;s sake.</p><blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow"><p>The right question isn&#039;t &#039;how much does custom software cost&#039;, but &#039;how much is standard software already costing me by forcing me to adapt&#039;</p></blockquote><p class="wp-block-paragraph">That&#039;s exactly why an IT consulting phase is valuable: before writing a single line of code, you need to analyze your business processes, identify where time is being lost, and understand which solution actually delivers real returns. It&#039;s the safest way to invest with confidence, avoiding choices driven purely by what&#039;s trendy at the moment.</p><h2 class="wp-block-heading">Signs Your Business Needs Custom Software</h2><p class="wp-block-paragraph">The need for tailored software rarely announces itself loudly and clearly. More often it emerges as small daily frictions that, added together, slow down work and increase costs without anyone really noticing. Spotting these warning signs early allows you to intervene before they become a bottleneck to growth.</p><p class="wp-block-paragraph">Here are the most common signals we encounter in SMEs that indicate a genuine opportunity for custom development:</p><ul class="wp-block-list"><li>Manual and repetitive tasks: every month someone spends hours copying data, generating reports, or sending communications that could be automated.</li><li>Spreadsheets everywhere: critical information scattered across dozens of different files, with versions that don&#039;t match and constant risk of errors or overwriting.</li><li>Disconnected data: accounting software, inventory management, sales systems and CRM all contain the same data, but none of these systems communicate with each other, forcing you to re-enter the same information multiple times.</li><li>Siloed software: tools purchased at different times that function as separate islands, with data transfers done manually or through manual exports.</li><li>Dependence on key people: some processes only work because a specific person &quot;knows how it&#039;s done,&quot; and everything grinds to a halt when they&#039;re unavailable.</li><li>Difficulty getting up-to-date numbers: finding out the real status of sales, orders, or inventory requires days of work and cross-referencing files.</li></ul><p class="wp-block-paragraph">If you recognize even just two or three of these symptoms, your company is likely paying a hidden cost made up of wasted time, errors, and decisions based on incomplete data. Often the problem isn&#039;t a lack of tools, but the way these tools are (or aren&#039;t) connected to each other.</p><blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow"><p>The costliest symptom isn&#039;t the occasional error, but the time people spend every day making systems communicate when they should already be talking to each other.</p></blockquote><p class="wp-block-paragraph">This is exactly where IT consulting comes in: analyzing business processes to understand where these friction points come from, distinguishing between what&#039;s worth solving with a custom solution and what can stay as is, and setting intervention priorities. A clear preliminary analysis prevents you from investing in development where it&#039;s not needed and focuses resources where the return is most evident.</p><h2 class="wp-block-heading">How a custom development project works: from needs to release</h2><p class="wp-block-paragraph">Many entrepreneurs shy away from custom software because they fear a long, unclear process that&#039;s hard to control. In reality, a well-managed project follows distinct phases, with clear checkpoints where you decide and approve. Let&#039;s see how it unfolds, step by step.</p><ul class="wp-block-list"><li>Needs analysis: together we clarify objectives, processes, and problems to solve. In this phase we listen to those who work with your business tools every day, because that&#039;s where the real needs come to light.</li><li>Design: we translate requirements into a concrete structure. We define features, workflows, and a visual concept of the application, so you can &#039;see&#039; the solution before it&#039;s even built.</li><li>Development: we start building the software in increments, so we can show you tangible results at regular intervals and adjust course without surprises at the end.</li><li>Testing: we verify that everything works as intended, checking reliability, security, and usability before the tool reaches your team&#039;s hands.</li><li>Release: we put the software into operation, supporting the launch and, where needed, training the people who will use it.</li><li>Maintenance: after launch we stay by your side for updates, improvements, and new needs that arise as your business grows.</li></ul><p class="wp-block-paragraph">When it comes to timing and involvement, it pays to be straightforward: we don&#039;t ask you to become a tech expert, but to share your business knowledge. Your effort is focused mainly on the analysis phase and periodic reviews—brief but crucial moments to keep the project aligned with your goals. Overall timelines depend on complexity, but the staged approach gives you constant visibility and lets you plan with confidence.</p><blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow"><p>A good project isn&#039;t measured only by the final software, but by the clarity with which you reach the release.</p></blockquote><p class="wp-block-paragraph">This is where IT consulting makes the difference: RENOR partners with you through every phase as your trusted reference point, helping you make informed decisions about processes and digital tools. The goal isn&#039;t simply to deliver a product, but to ensure the solution is truly useful, sustainable over time, and aligned with how your business operates.</p><h2 class="wp-block-heading">The role of IT consulting: more than just code, it&#039;s strategy</h2><p class="wp-block-paragraph">When people think about a software project, attention almost always focuses on the development phase. In reality, the part that determines the success or failure of a technology investment comes before a single line of code is written. This is where IT consulting comes in: a work of analysis and guidance that transforms a business need into a concrete plan, sustainable over time and aligned with business objectives.</p><p class="wp-block-paragraph">Choosing the right technologies, deciding whether to adopt cloud solutions, understanding how to make existing company systems work together: these are decisions that have direct consequences on costs, timelines, and future flexibility. A wrong choice at this stage can mean having to redo the work in a few years, or ending up with tools that don&#039;t communicate with each other and create duplicate work instead of simplifying it.</p><p class="wp-block-paragraph">For a business owner or non-technical manager, the value of consulting lies precisely in this: having someone at your side who translates business priorities into motivated technology choices, explained in an understandable way. It&#039;s not about adding complexity, but about reducing risk and making informed decisions.</p><h2 class="wp-block-heading">The questions consulting answers before development begins</h2><ul class="wp-block-list"><li>Which technologies are truly suited to your context, and which risk becoming a constraint?</li><li>Does it make sense to move to the cloud, and to what extent, based on your real needs?</li><li>How do you integrate the new software with the management systems and tools already in use?</li><li>What are the priorities to invest in right now and which ones can wait?</li></ul><p class="wp-block-paragraph">This is exactly what our IT Consulting service does: supporting SMEs in defining technology choices before starting any development, so you can move forward with a clear direction. Viewing it as the starting point, rather than an optional step, is often what sets a project that delivers value apart from one that becomes just another cost.</p><blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow"><p>The best technology isn&#039;t the most advanced one—it&#039;s the one that truly meets your company&#039;s goals.</p></blockquote><h2 class="wp-block-heading">Web apps, cloud platforms and choosing the right vendor</h2><p class="wp-block-paragraph">When it comes to custom software for an SME, today&#039;s most common path is no longer a program installed on every single computer, but browser-based solutions hosted in the cloud. Understanding the difference helps you make more informed decisions, even without technical expertise.</p><p class="wp-block-paragraph">A web app is an application you use directly from your browser, with no installations needed: your team members log in with their office credentials from the office, home, or while on the go. Cloud platforms, on the other hand, refer to where the application and data actually live: not on a physical server at your company, but on infrastructure managed by specialized providers, with updates and security included.</p><h2 class="wp-block-heading">What concrete benefits for SMEs</h2><ul class="wp-block-list"><li>Access from anywhere and any device, ideal for distributed teams or those on the road</li><li>No need to buy and maintain servers in-house, with more predictable costs</li><li>Gradual growth: start with a few features and add modules as you need them</li><li>Updates and backups managed continuously, without disrupting your work</li></ul><p class="wp-block-paragraph">Technology, however, is only as good as the people who build it. Choosing the right vendor is often more important than the programming language used: a reliable partner understands your business, not just the code.</p><h2 class="wp-block-heading">Criteria for selecting the right software development company</h2><ul class="wp-block-list"><li>Listening skills: translates your real processes into clear requirements, before suggesting solutions</li><li>Transparency about timelines, costs and working methods, without empty promises</li><li>Experience with companies similar to yours in size and industry</li><li>Long-term support: what happens after launch, including fixes, updates and assistance</li><li>Ownership of the software and data clearly defined in your favor</li></ul><p class="wp-block-paragraph">This is where IT Consulting set up as an ongoing relationship comes into play: supporting you in evaluating technical options and choosing the most sustainable path for your company, avoiding over-engineered investments or solutions that become outdated quickly.</p><p class="wp-block-paragraph">If you want to explore specific aspects further, you&#039;ll find dedicated articles on web apps, cloud platforms and managing a software project, useful for approaching a vendor with a clearer understanding.</p><h2 class="wp-block-heading">How much it costs and how to evaluate return on investment</h2><p class="wp-block-paragraph">The question about costs is legitimate and deserves an honest answer: there is no fixed price for custom software, because every project starts from different needs. A management system to coordinate a few departments requires a very different effort than a platform that integrates suppliers, inventory, and customers. That&#039;s why, rather than asking &quot;how much does software cost&quot;, it&#039;s better to understand which factors influence the quote.</p><p class="wp-block-paragraph">The main factors that determine the investment are these:</p><ul class="wp-block-list"><li>The complexity of the processes to be digitized and the number of features required</li><li>Integrations with tools already in use (ERP systems, e-commerce, external services)</li><li>The number of users and the volume of data to manage over time</li><li>The level of customization of the interface and user experience</li><li>Maintenance, updates, and support after release</li></ul><p class="wp-block-paragraph">It&#039;s also important to consider costs that often go unnoticed when you postpone the decision: hours wasted on manual tasks, errors to correct, duplicate data, delays in customer responses. These inefficiencies have a real price, even if they don&#039;t appear on any invoice.</p><h2 class="wp-block-heading">How to estimate return on investment</h2><p class="wp-block-paragraph">The ROI of custom software is measured by comparing the initial investment with the benefits it generates over time. A simple method is to quantify the hours saved each month thanks to automation, multiply them by the hourly cost of the people involved, and project the savings over one or two years. To this should be added the less immediate but very real advantages: fewer errors, faster decisions thanks to reliable data, greater capacity to grow without increasing staff.</p><blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow"><p>Well-designed software is not an expense that ends: it&#039;s an investment that continues to deliver value every month that passes.</p></blockquote><p class="wp-block-paragraph">This is where IT consulting shows its value. Before talking about figures, it&#039;s useful to analyze your processes together, identify where inefficiencies are concentrated, and define priorities. With our IT consulting, we help SMEs do exactly this: transform concrete needs into a clear plan, with an estimate of costs and expected benefits. If you want to understand which investment really makes sense for your business, requesting personalized consulting is the first step to getting concrete numbers to base your decision on.</p><h2 class="wp-block-heading">Getting Started with RENOR &amp; Partners</h2><p class="wp-block-paragraph">After exploring why custom software can make a real difference, how a project is structured, and how to measure its return, there&#039;s one more practical question left: what&#039;s the first step? The answer is simpler than it might seem. You don&#039;t need to have your mind made up about technologies, timelines, or budget. All you need is the willingness to understand whether and where a targeted intervention can improve your company&#039;s day-to-day operations.</p><p class="wp-block-paragraph">We always start by listening. Before proposing any solution, we want to understand how your business truly works: which processes are slowing you down, where time and information are lost, what tools you&#039;re already using, and what you expect to achieve. This is where our IT Consulting comes in—designed to support decision-makers and translate operational needs into sound technology choices, without unnecessary jargon.</p><p class="wp-block-paragraph">An initial assessment lets you get concrete answers before committing significant resources.</p><ul class="wp-block-list"><li>Determine whether custom software is truly the most effective choice for your situation, or if faster alternatives exist.</li><li>Identify priorities: which process should you start with to get the most benefit in the shortest time.</li><li>Get a realistic picture of timelines, working methods, and the expected return on your investment.</li></ul><p class="wp-block-paragraph">This way, you immediately connect the two aspects we&#039;ve covered throughout this guide: consulting, which defines strategy and priorities, and custom development, which turns that strategy into a concrete tool tailored to your reality.</p><blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow"><p>You don&#039;t need to know what you need yet: our job is to help you discover it through a clear, no-strings conversation.</p></blockquote><p class="wp-block-paragraph">If you recognize even just some of the signals and needs described in this guide within your company, now is the right time to act. Contact RENOR &amp; Partners for an initial assessment: we&#039;ll analyze your situation together and tell you honestly and concretely where it makes sense to start. It will be your first step toward understanding how our IT Consulting and custom development can work to serve your goals.</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>Need concrete support?</strong> Discover our <a href="https://renor.it/en/services/it-consulting/">IT Consulting</a> service or <a href="https://renor.it/en/contact-us/">contact us</a> for a consultation.</p></div></div><p>L'articolo <a href="https://renor.it/en/blog/software-development-programming/it-consulting-custom-software-development-for-smes/">IT Consulting and Custom Software for SMEs: The Complete Guide</a> proviene da <a href="https://renor.it/en/">RENOR &amp; Partners S.r.l.</a>.</p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Custom Web App: How to Choose the Right Company in Italy for Your Project</title>
		<link>https://renor.it/en/blog/sviluppo-software-programmazione/custom-web-app-development-company-italy/</link>
		
		<dc:creator><![CDATA[Simone Renzi]]></dc:creator>
		<pubDate>Tue, 08 Sep 2026 10:58:56 +0000</pubDate>
				<category><![CDATA[Software Development & Programming]]></category>
		<category><![CDATA[digital transformation]]></category>
		<category><![CDATA[innovation]]></category>
		<category><![CDATA[renor]]></category>
		<category><![CDATA[technology]]></category>
		<guid isPermaLink="false">https://renor.it/blog/sviluppo-software-programmazione/custom-web-app-development-company-italy/</guid>

					<description><![CDATA[<p>Discover how to choose the right company to develop your custom web app in Italy. Tips and criteria to find the perfect technology partner for your</p>
<p>L'articolo <a href="https://renor.it/en/blog/sviluppo-software-programmazione/custom-web-app-development-company-italy/">Custom Web App: How to Choose the Right Company in Italy for Your Project</a> proviene da <a href="https://renor.it/en/">RENOR &amp; Partners S.r.l.</a>.</p>
]]></description>
										<content:encoded><![CDATA[<h2 class="wp-block-heading">What is a custom web app (and why off-the-shelf software isn&#039;t enough)</h2><p class="wp-block-paragraph">A custom web app is a browser-based application built specifically to address your company&#039;s unique needs. Unlike off-the-shelf software, which comes with predetermined features that work the same way for everyone, a custom web app is designed around your actual workflows: how you manage orders, engage with clients, coordinate inventory, or generate your reports.</p><p class="wp-block-paragraph">Off-the-shelf software has clear advantages: it costs less upfront, it&#039;s ready to use immediately, and the vendor handles updates. For most basic operations it&#039;s more than sufficient. The problem emerges when your company has to adapt its way of working to fit the software, rather than the other way around. You end up with features you don&#039;t need, manual workarounds to fill the gaps, and separate tools that don&#039;t talk to each other.</p><p class="wp-block-paragraph">Custom solutions make sense when your processes are a competitive differentiator or too specialized for a generic product. Here are some concrete signs:</p><ul class="wp-block-list"><li>You&#039;re juggling multiple Excel sheets or disconnected tools just to keep your information together.</li><li>Your current management system forces you to repeat manual tasks every single day.</li><li>You need to connect different systems into one seamless workflow.</li><li>The way you operate is a competitive advantage that no off-the-shelf software can replicate.</li></ul><blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow"><p>The right question isn&#039;t &quot;how much does it cost,&quot; but &quot;how much is it already costing me to keep working inefficiently.&quot;</p></blockquote><p class="wp-block-paragraph">To be honest: custom development requires a larger upfront investment and longer implementation timelines. In return, you get a tool that evolves with your business, without paying for features you&#039;ll never use and without having to overhaul your operations every time the vendor pushes an update.</p><p class="wp-block-paragraph">Another often-overlooked aspect is where your application will live. Development and cloud infrastructure need to be thought through together from day one: cloud-based infrastructure lets you scale your web app as your business grows, makes it accessible from anywhere, and gives you more flexibility in managing updates and security. Choosing custom means deciding not just what to build, but also the technical foundation it sits on—so you&#039;re not caught short the moment your business starts scaling up.</p><h2 class="wp-block-heading">Signs Your Business Needs a Custom Web App</h2><p class="wp-block-paragraph">Many companies continue to work with tools that no longer fit their needs, simply because change feels complicated or risky. The problem is that symptoms of an inadequate system rarely blow up all at once—they pile up day by day, in the form of lost hours, recurring mistakes, and decisions made without solid data. Spotting them early is the first step in understanding whether an investment in custom development truly makes sense for your business.</p><p class="wp-block-paragraph">Here are some concrete warning signs that come up regularly when we talk to entrepreneurs and operations managers:</p><ul class="wp-block-list"><li>Your team spends hours copying data from one Excel sheet to another, or manually filling in the same fields across multiple disconnected systems.</li><li>The software you use is rigid: making even a simple change to your workflow requires workarounds, expensive plugins, or compromises.</li><li>Information lives scattered across emails, spreadsheets, chat apps, and disconnected software, and nobody has a single, up-to-date view.</li><li>Getting a reliable report means someone has to stop for half a day to cross-reference different sources, often arriving too late to inform decisions.</li><li>A critical process depends on one person who &quot;knows how it works,&quot; with minimal documentation and high risk if they&#039;re unavailable.</li><li>Work volume keeps growing, but the only way to handle it seems to be hiring more people just to do repetitive tasks.</li></ul><p class="wp-block-paragraph">If you recognize yourself in three or more of these points, you likely don&#039;t have a people problem—you have a tools problem. Your systems aren&#039;t keeping up with how you actually work. This is exactly where a custom web app delivers real value: it automates manual steps, centralizes your data, and adapts the software to your processes instead of forcing you to adapt to the software.</p><blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow"><p>The question isn&#039;t &quot;can we keep going like this?&quot;, but &quot;how much does it cost us to keep going like this every month?&quot;.</p></blockquote><p class="wp-block-paragraph">Turning these warning signs into a stable, accessible solution requires solid development and cloud expertise: an application built for your workflow, reliably hosted in the cloud, and ready to scale alongside your business. That&#039;s where choosing the right partner comes in—the subject we&#039;ll dive into in the sections ahead.</p><h2 class="wp-block-heading">How to evaluate a web app development company in Italy: 7 criteria</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">Choosing the right partner is the decision that determines project success more than the technologies used. To navigate this choice without becoming a technical expert, here are seven concrete criteria to verify before signing any contract.</p><ul class="wp-block-list"><li>Real cloud expertise: ask about the infrastructures they typically work with (for instance the major providers) and how they handle scalability and service continuity. A solid company in development and cloud knows how to size the solution based on projected growth, without disproportionate costs for occasional spikes.</li><li>Transparent working method: verify how they organize the project into phases, how often they show progress updates, and how they collect your feedback. An iterative approach with progressive releases reduces the risk of discovering problems only at the end.</li><li>Maintenance and post-launch support: a web app is not a product you hand over and forget about. Ask what the contract covers after release: updates, bug fixes, response times, and who to contact in case of issues.</li><li>Security and data protection: find out how they protect access, where data resides, and how they comply with privacy regulations. This is an aspect that safeguards your company and your customers.</li><li>Verifiable references: don&#039;t stop at their portfolio. Ask to speak with previous clients, ideally from the same industry or with needs similar to yours.</li><li>Financial clarity: detailed quotes with understandable line items and no hidden costs. Be wary of prices that are too low—they often hide work that&#039;s not included.</li><li>Code ownership and continuity: ensure that the software developed remains your property and that, should you switch providers, everything is properly documented and transferable.</li></ul><p class="wp-block-paragraph">A reliable partner will answer these questions with concrete details, without vagueness or generic promises. If you&#039;re looking for a partner with established expertise in development and cloud, capable of guiding your project from design through ongoing maintenance, talking with us is the first step to see if there&#039;s the right fit.</p><blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow"><p>The most underrated criterion is not what the provider can do today, but whether they&#039;ll still be at your side in two years.</p></blockquote><h2 class="wp-block-heading">The phases of a custom development project, from idea to launch</h2><p class="wp-block-paragraph">A custom development project never starts directly with code. It follows a structured path, made up of defined steps, that transforms a business need into a working and reliable tool. Understanding these phases helps you know what to expect, when to make decisions, and how to track progress.</p><p class="wp-block-paragraph">Here are the main stages that a professional partner will propose:</p><ul class="wp-block-list"><li>Discovery: we start from your objectives and your company&#039;s actual processes. This phase defines priority features, constraints, and expected outcomes. This is when ideas become concrete requirements.</li><li>Prototyping: before writing the software, we build sketches and clickable wireframes. Previewing how the web app will work reduces misunderstandings and lets you course-correct when the cost of changes is still low.</li><li>Development: this is where the real product takes shape. A good vendor works in successive iterations, releasing usable pieces incrementally, so you see tangible progress without waiting for everything to be finished.</li><li>Testing: each feature is verified to ensure it does what it should, even in unexpected scenarios. Quality checks cover correctness, security, and behavior under realistic data volumes.</li><li>Cloud deployment: the web app goes live on reliable infrastructure, ready to scale as usage grows. Releasing to the cloud ensures accessibility, managed updates, and service continuity.</li></ul><p class="wp-block-paragraph">The value of this approach lies not only in the final product, but in predictability: you always know where you stand, what&#039;s been decided, and what remains to be done. Reducing uncertainty means reducing the risk of your investment.</p><blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow"><p>A well-managed project isn&#039;t one without surprises, but one where surprises surface early and are handled methodically.</p></blockquote><p class="wp-block-paragraph">This is exactly what our Development and cloud service focuses on: guiding your project from design through to online launch, following a structured path that brings together software development and cloud infrastructure deployment. So your idea doesn&#039;t stay as a specification document, but becomes a live tool available to your users.</p><h2 class="wp-block-heading">How much does a custom web app cost and how long does it take</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">It&#039;s the first question every business owner asks, and it&#039;s a fair one. The honest answer is: it depends. Not to avoid the question, but because a tailor-made web app isn&#039;t an off-the-shelf product with a fixed price list. Cost and timeline vary based on feature complexity, the number of integrations with external systems, the volume of data to manage, and the level of UI customization. That said, there are concrete criteria to get a realistic sense of things before even requesting a quote.</p><p class="wp-block-paragraph">Generally speaking, in the Italian market a project can fall into three indicative price ranges:</p><ul class="wp-block-list"><li>Small project (MVP or simple management system): between a few thousand and 15-20 thousand euros, with a timeline of 1-3 months. Useful for validating an idea or covering a single business process.</li><li>Medium project (multiple modules, user roles, integrations): between 20 and 60 thousand euros, with a timeline of 3-6 months. This is the most common range for SMBs digitizing a real workflow.</li><li>Large project (complex platform, high scalability, many integrations): over 60 thousand euros with timelines that can exceed 6-12 months.</li></ul><p class="wp-block-paragraph">These numbers are meant to guide you, not to quote a price: only an analysis of your requirements gives you a reliable estimate. A common mistake is thinking only about the initial cost. A web app needs to be hosted, maintained, and updated over time: this is where recurring cloud infrastructure, monitoring, and maintenance expenses come in—often underestimated. This is precisely where our development and cloud service comes in, pairing app development with environment management so you don&#039;t get surprises after launch.</p><blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow"><p>A quote that&#039;s too low and too fast is rarely a good deal: it usually means requirements weren&#039;t understood or costs that will surface later.</p></blockquote><p class="wp-block-paragraph">The best way to reduce uncertainty is to start by discussing your concrete goals. From there, budget and timelines stop being abstract numbers and become a roadmap for making decisions with confidence. If you have a need in mind, requesting a quote is the first step to turning it into a measurable estimate.</p><h2 class="wp-block-heading">Why choose RENOR &amp; Partners for your web app</h2><p class="wp-block-paragraph">After exploring which criteria to use when selecting a provider and how a project takes shape, a concrete question remains: who can you really trust? RENOR &amp; Partners was founded to guide SMEs and professionals through digital transformations rooted in real needs, not off-the-shelf solutions. Our goal isn&#039;t to sell you code—it&#039;s to build a tool that streamlines daily operations and fuels your business growth over time.</p><p class="wp-block-paragraph">Our Development and cloud services handle building your custom web app and deploying it in a reliable, scalable environment. This means you don&#039;t just get a working application: you also get infrastructure designed to grow with you, without needing to rebuild everything when your user base or data load expands.</p><p class="wp-block-paragraph">Before development even begins, our IT Consulting team helps you prioritize what matters most before writing a single line of code. This is where we turn an idea or operational challenge into a clear project plan, complete with measurable goals and well-reasoned technical choices. For those without internal technical expertise, this step saves costly mistakes and decisions driven by short-term enthusiasm.</p><p class="wp-block-paragraph">In practical terms, working with us means having a partner who speaks your language, explains every choice, and brings you into decisions that truly matter. Here&#039;s what you can expect:</p><ul class="wp-block-list"><li>A point of contact who translates business goals into clear technical requirements</li><li>Custom development and cloud deployment built for reliability and scalability</li><li>A transparent process, from initial consulting through go-live</li><li>Focus on the specific needs of SMEs and professionals, without overengineering</li></ul><p class="wp-block-paragraph">If you&#039;re evaluating a custom web app and want to confirm it&#039;s the right move, the best way to start is to discuss your goals, timeline, and budget. Book a strategic consultation with RENOR &amp; Partners: we&#039;ll review your situation together and map out the first concrete step, with no obligation.</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>Need concrete support?</strong> Discover our <a href="https://renor.it/en/services/development-and-cloud/">Development and cloud</a> service or <a href="https://renor.it/en/contact-us/">contact us</a> for a consultation.</p></div></div><p>L'articolo <a href="https://renor.it/en/blog/sviluppo-software-programmazione/custom-web-app-development-company-italy/">Custom Web App: How to Choose the Right Company in Italy for Your Project</a> proviene da <a href="https://renor.it/en/">RENOR &amp; Partners S.r.l.</a>.</p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Custom ERP: How to Build a Management System Tailored to Your Company</title>
		<link>https://renor.it/en/blog/sviluppo-software-programmazione/custom-erp-implementation-business-management-system/</link>
		
		<dc:creator><![CDATA[Simone Renzi]]></dc:creator>
		<pubDate>Mon, 07 Sep 2026 11:09:06 +0000</pubDate>
				<category><![CDATA[Software Development & Programming]]></category>
		<category><![CDATA[automation]]></category>
		<category><![CDATA[digital transformation]]></category>
		<category><![CDATA[innovation]]></category>
		<category><![CDATA[renor]]></category>
		<guid isPermaLink="false">https://renor.it/blog/sviluppo-software-programmazione/custom-erp-implementation-business-management-system/</guid>

					<description><![CDATA[<p>Discover how to build a custom ERP management system perfect for your company. Complete guide to choosing and implementing a tailored system solution.</p>
<p>L'articolo <a href="https://renor.it/en/blog/sviluppo-software-programmazione/custom-erp-implementation-business-management-system/">Custom ERP: How to Build a Management System Tailored to Your Company</a> proviene da <a href="https://renor.it/en/">RENOR &amp; Partners S.r.l.</a>.</p>
]]></description>
										<content:encoded><![CDATA[<h2 class="wp-block-heading">Off-the-shelf ERP or custom management software: what&#039;s the difference</h2><p class="wp-block-paragraph">An ERP (Enterprise Resource Planning) is a software system that brings together all of your business processes in one place: sales, purchasing, inventory, accounting, production, and human resources management. The goal is to connect information that often lives scattered across spreadsheets, emails, and different applications, giving you a clear and up-to-date picture of what&#039;s happening in your company.</p><p class="wp-block-paragraph">The difference between a standard ERP and custom management software lies in where you start. Packaged ERP is a ready-made product: it offers a set of predefined features that work well for many businesses, but it expects you to reshape how you work to match how the software was designed. Custom software does the opposite: it starts from your actual processes and builds tools around them, including only what you really need.</p><p class="wp-block-paragraph">To figure out which path makes sense for you, it helps to look at some concrete differences:</p><ul class="wp-block-list"><li>Adaptation: standard software imposes its workflows; custom software follows yours.</li><li>Features: packaged solutions include many functions you may never use; custom solutions cover exactly what you need.</li><li>Growth: custom management software scales with your business, integrating with the tools you already use.</li><li>Competitive advantage: if a particular process is your strength, custom software amplifies it rather than flattening it into a generic template.</li></ul><p class="wp-block-paragraph">There&#039;s no universally right choice. A company with straightforward, standardized processes might find that packaged ERP offers a quick and cost-effective solution. But if you have unique workflows, specific requirements, or want to turn your procedures into a hard-to-replicate competitive edge, you&#039;ll get more value from a custom development approach.</p><blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow"><p>The real question isn&#039;t just &quot;what software do I need,&quot; but &quot;who adapts to whom&quot;: do I adjust to the program, or does the program adjust to me?</p></blockquote><p class="wp-block-paragraph">This is where custom development and cloud infrastructure come in: building management software designed specifically for your company&#039;s reality and delivered securely, wherever and whenever you need it. In the sections ahead, we&#039;ll walk through how you actually get to a solution like this.</p><h2 class="wp-block-heading">When a custom ERP really makes sense (and when it doesn&#039;t)</h2><p class="wp-block-paragraph">The right question isn&#039;t &quot;is a tailored system better?&quot;, but &quot;does my business have needs that standard software can&#039;t address?&quot;. In most cases, the answer depends on how much your processes differ from what&#039;s already available on the market. If you operate in a linear way that&#039;s common to your industry, a standard solution is often faster and more cost-effective. But if your way of doing business is part of your competitive advantage, forcing it into a pre-packaged mold risks slowing you down.</p><p class="wp-block-paragraph">There are three concrete signals that show when custom development truly pays for the investment.</p><ul class="wp-block-list"><li>Non-standard processes: if your workflows (production, logistics, order management, quality control) follow particular logic and you currently manage them with Excel sheets, emails, or manual steps, an ERP built around these processes eliminates errors and wasted time.</li><li>Specific integrations: if you need your system to communicate with machinery, e-commerce platforms, customer portals, shipping providers, or existing software, a custom project can be designed with these connections in mind from the start, rather than adapting to limited integration options.</li><li>Rapid growth or evolving business model: if you&#039;re scaling, opening new locations, or changing your business model, you need a tool that grows with you—not a constraint you&#039;ll need to overhaul in two years.</li></ul><p class="wp-block-paragraph">Conversely, a custom ERP is often an unjustified expense when volumes are low, processes are simple and replicable, or the company isn&#039;t yet ready to clearly define how it operates. In these cases, it&#039;s better to start with a standard solution and consider customization only where real limitations emerge.</p><blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow"><p>The practical rule: customize what sets you apart, standardize what everyone has in common.</p></blockquote><p class="wp-block-paragraph">If you recognize your business in one of these signals, the next step is understanding how to structure the project. This is where development and cloud expertise come in, enabling you to build a system designed around your processes and securely accessible from multiple locations and devices, evolving with your business over time.</p><h2 class="wp-block-heading">The phases of implementing a custom ERP solution</h2><p class="wp-block-paragraph">Building a custom ERP doesn&#039;t mean &quot;writing code&quot; from day one. It&#039;s a structured journey where each phase reduces uncertainty and lays the groundwork for the next. Understanding these steps helps you know what to expect, which decisions fall to you, and how to keep timelines and budgets in check.</p><h2 class="wp-block-heading">1. Process Analysis</h2><p class="wp-block-paragraph">It all starts with understanding how your company really works: workflows, roles, critical pain points, and repetitive activities that waste time today. This phase involves gathering input from the people who will use the software every day. The goal isn&#039;t to replicate existing habits, but to identify what to improve and what to automate.</p><h2 class="wp-block-heading">2. Design</h2><p class="wp-block-paragraph">The information gathered becomes a concrete plan: which modules you need, how they&#039;ll communicate with each other, and what the user experience will look like. Defining functionality and priorities upfront prevents surprises and allows you to estimate resources and release timelines accurately.</p><h2 class="wp-block-heading">3. Development</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">This is when the system takes shape. An effective approach uses progressive releases: essential features are built first, so you can see them in action and provide feedback, rather than waiting months for a finished product. Our development and cloud services fit squarely here, designed to build tailored solutions and make them reliably accessible.</p><h2 class="wp-block-heading">4. Integration</h2><p class="wp-block-paragraph">An ERP rarely works in isolation. It needs to connect with the tools you already use, so data flows seamlessly without duplicate entry. Good integration is what transforms the system into a true command center for your business.</p><h2 class="wp-block-heading">5. Testing and Release</h2><p class="wp-block-paragraph">Before going live, the system is tested under real conditions to catch errors and refine details. The release is accompanied by team training, so adoption is fast. It&#039;s not an endpoint: a custom ERP evolves over time as your company grows.</p><blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow"><p>A clear methodology, made up of distinct and verifiable phases, is the first safeguard against unexpected issues, runaway costs, and projects that never reach the finish line.</p></blockquote><h2 class="wp-block-heading">Modules and integrations: from warehouse to CRM</h2><p class="wp-block-paragraph">The true value of a customized ERP lies in its ability to connect different areas of your business. Instead of managing information scattered across spreadsheets, separate software, and email inboxes, a tailored management system collects data in a single, unified environment. Each module handles a specific function, but all share the same information updated in real time.</p><p class="wp-block-paragraph">An ERP is built by combining only the modules that truly matter to your business, without paying for features you&#039;ll never use. Here are the areas most requested by SMEs:</p><ul class="wp-block-list"><li>Warehouse and logistics: stock levels, movements, automatic reordering, and batch traceability, so you always know what you have and where it is.</li><li>Purchasing and suppliers: order management, payment terms, and price lists, with a complete history of all supplies.</li><li>Sales and billing: quotes, customer orders, shipping documents, and invoices, directly linked to accounting.</li><li>Production: bill of materials, production progress tracking, and actual cost calculation.</li><li>Reporting and dashboards: key metrics always at your fingertips to make decisions based on real data.</li></ul><p class="wp-block-paragraph">A customized system&#039;s power emerges when these modules integrate with the tools you already use: e-commerce portal, electronic invoicing system, your accountant&#039;s accounting software, or shipping platforms. A well-designed integration eliminates duplicate data entry and reduces manual errors that slow down daily operations.</p><p class="wp-block-paragraph">Among the most strategic integrations is the one with CRM, the module dedicated to customer relationships. Linking customer records, orders, and communications lets your sales team see at a glance each customer&#039;s history: purchases, pending offers, support requests, and deadlines. For an SME, a customized CRM means managing relationships based on concrete criteria aligned with your processes, rather than adapting to rigid software designed for someone else.</p><p class="wp-block-paragraph">Making all this accessible and reliable is a matter of infrastructure. With a development and cloud-oriented approach, your ERP&#039;s modules and integrations can be available everywhere and securely, enabling those working on-site, traveling, or remotely to operate on the same updated data.</p><h2 class="wp-block-heading">How much does a custom ERP cost and how to budget for it</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">It&#039;s the first question every business owner asks, but there&#039;s no fixed price list. A custom ERP isn&#039;t an off-the-shelf product: it&#039;s a project built around your company&#039;s processes. That&#039;s why the budget is estimated, not read from a catalog. The good news is that the factors determining the cost are clear and predictable, and knowing them allows you to make informed decisions from your first conversation with a vendor.</p><p class="wp-block-paragraph">The cost essentially depends on the complexity of what you want to automate. The more articulated or specific your processes are, the more analysis and development work increases. Here are the main factors that weigh on a quote:</p><ul class="wp-block-list"><li>Number and complexity of required modules (inventory, CRM, production, accounting): each area adds dedicated logic and development.</li><li>Integrations with software and systems already in use: connecting management systems, e-commerce platforms or external tools requires custom technical work.</li><li>Degree of customization of workflows compared to standard solutions.</li><li>Number of users and roles with different permissions and views.</li><li>Migration of historical data from current systems, often underestimated but decisive.</li><li>Maintenance, updates and support after release.</li></ul><p class="wp-block-paragraph">Another element that affects costs, often in a positive way, is the choice of infrastructure. An approach based on development and cloud computing allows you to avoid significant initial investments in servers and hardware, spreading expenses over time and adapting resources to the company&#039;s actual growth. Essentially, you pay for what you use, with greater flexibility both at startup and in the years that follow.</p><blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow"><p>The true cost of an ERP isn&#039;t just the initial development, but the total over three to five years: development, maintenance, evolution and infrastructure.</p></blockquote><p class="wp-block-paragraph">To build a reliable estimate, the advice is to start with an analysis of priority processes and define a contained initial scope, to be expanded gradually. A phased project approach allows you to control investment and see concrete results before committing the entire budget. For a detailed breakdown of all cost items, we refer you to our complete guide to enterprise software project costs.</p><h2 class="wp-block-heading">Cloud, security and maintenance over time</h2><p class="wp-block-paragraph">A custom management system is not a project that ends at delivery: it&#039;s a tool that supports the company for years. This is why the infrastructure it runs on and the activities that ensure its continuity matter just as much as the features themselves. An ERP built well but hosted poorly, or left without updates, quickly becomes a liability instead of an asset.</p><p class="wp-block-paragraph">Hosting the management system in the cloud means not having to worry about managing physical servers, reducing initial hardware costs, and being able to scale resources as the company grows. If the number of users, locations, or data volumes increase, the infrastructure scales without requiring a complete overhaul. Plus, access from multiple workstations and on the move becomes seamless—a critical feature for those working at job sites, branch offices, or with external partners.</p><h2 class="wp-block-heading">Security is not optional</h2><p class="wp-block-paragraph">The management system contains your company&#039;s most sensitive data: client records, prices, margins, inventory. Protecting it means implementing some basic measures that should always be part of the design.</p><ul class="wp-block-list"><li>Regular and automatic backups, with genuine capability to restore data if problems occur</li><li>Role-based access controls, so each person sees only what they need to</li><li>Timely updates to fix vulnerabilities and keep the system reliable</li><li>Infrastructure monitoring to intervene before an issue stops work</li></ul><p class="wp-block-paragraph">Maintenance over time goes beyond security alone. Regulations change, business processes evolve, new needs emerge: a custom management system must be able to grow with your business, through planned improvements rather than reactive fixes. Having a partner that manages both development and cloud infrastructure eliminates the typical finger-pointing between software developers and server administrators, reducing response times and removing unclear responsibilities.</p><blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow"><p>With our Development and cloud service we support your management system continuously: from creation to the infrastructure that hosts it, so you have one point of contact over time.</p></blockquote><p class="wp-block-paragraph">In practice, evaluating from the start where and how the management system will live and who will care for it over the years is an integral part of a well-executed project: it&#039;s what transforms good software into a tool you can rely on every single day.</p><h2 class="wp-block-heading">How RENOR &amp; Partners builds your custom ERP</h2><p class="wp-block-paragraph">After exploring phases, modules, budgets, and timeline management, the most practical question remains: who should you trust with such a critical project? The value of a tailor-made ERP depends not just on the code itself, but on the methodology behind its construction and on the ability to translate your company&#039;s actual processes into a tool that truly simplifies them.</p><p class="wp-block-paragraph">Our approach starts with listening. Before writing a single line of software, we invest time in understanding how you work today: where time is wasted, which data gets duplicated, which steps generate errors. Only this way can we design a management system that adapts to your organization, not the other way around.</p><p class="wp-block-paragraph">Through our Development and Cloud service, we guide your company through the entire journey, never leaving you alone during critical moments.</p><ul class="wp-block-list"><li>Process analysis: we map workflows, roles, and priorities together to define what you truly need and what can wait for a later phase.</li><li>Custom development: we build features in a modular way, so you can start with the essentials and scale your management system over time.</li><li>Cloud and continuity: we make your ERP securely accessible, with infrastructure designed for reliability and data availability.</li><li>Ongoing support: we remain by your side even after launch, providing updates, enhancements, and assistance.</li></ul><p class="wp-block-paragraph">This means no surprises and no dependency on rigid solutions: every technical choice is explained in a way you can understand, because you decide the project&#039;s priorities based on your business goals.</p><blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow"><p>A good ERP goes unnoticed—you only realize it&#039;s there because every work day becomes simpler and more organized.</p></blockquote><p class="wp-block-paragraph">If you&#039;re evaluating a custom management system for your business, the best way to start is to speak with someone who builds them every day. Contact us for a consultation through our Development and Cloud service page: we&#039;ll analyze your situation together and help you understand, with no obligation, whether a custom ERP is the right choice and where to begin.</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>Need concrete support?</strong> Discover our <a href="https://renor.it/en/services/development-and-cloud/">Development and cloud</a> service or <a href="https://renor.it/en/contact-us/">contact us</a> for a consultation.</p></div></div><p>L'articolo <a href="https://renor.it/en/blog/sviluppo-software-programmazione/custom-erp-implementation-business-management-system/">Custom ERP: How to Build a Management System Tailored to Your Company</a> proviene da <a href="https://renor.it/en/">RENOR &amp; Partners S.r.l.</a>.</p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Custom CRM Development for SMEs: When It&#8217;s Worth It and What to Consider</title>
		<link>https://renor.it/en/blog/sviluppo-software-programmazione/custom-crm-development-for-smes/</link>
		
		<dc:creator><![CDATA[Simone Renzi]]></dc:creator>
		<pubDate>Sun, 06 Sep 2026 10:47:16 +0000</pubDate>
				<category><![CDATA[Software Development & Programming]]></category>
		<category><![CDATA[automation]]></category>
		<category><![CDATA[digital transformation]]></category>
		<category><![CDATA[renor]]></category>
		<category><![CDATA[renor & partners]]></category>
		<guid isPermaLink="false">https://renor.it/blog/sviluppo-software-programmazione/custom-crm-development-for-smes/</guid>

					<description><![CDATA[<p>Discover when custom CRM development is worth it for your SME and identify key factors to evaluate for informed and profitable decision-making.</p>
<p>L'articolo <a href="https://renor.it/en/blog/sviluppo-software-programmazione/custom-crm-development-for-smes/">Custom CRM Development for SMEs: When It&#8217;s Worth It and What to Consider</a> proviene da <a href="https://renor.it/en/">RENOR &amp; Partners S.r.l.</a>.</p>
]]></description>
										<content:encoded><![CDATA[<h2 class="wp-block-heading">Custom CRM or off-the-shelf solution: what your SME really needs</h2><p class="wp-block-paragraph">A CRM (Customer Relationship Management) is the tool with which a company collects and organizes all information about its customers and business contacts: company details, ongoing negotiations, quotes sent, purchase history, communications, and activities to complete. In practice, it replaces scattered spreadsheets, personal notes, and email inboxes where information gets lost. The goal is straightforward: always know where each customer stands and never miss an opportunity.</p><p class="wp-block-paragraph">Two main paths exist in the market. The first is ready-made software: pre-packaged solutions available as subscriptions that activate quickly and cover the most common needs. The second is custom development: a CRM built around your company&#039;s specific processes, your sales workflows, and the way your people actually work.</p><p class="wp-block-paragraph">Neither option is objectively better: it depends on how you operate. To figure out which side you&#039;re on, evaluate these factors:</p><ul class="wp-block-list"><li>Are your business processes standard, or do they include particular steps that no generic software can represent?</li><li>Do you find yourself adapting the way your team works to fit the tool, instead of the other way around?</li><li>Do you need to connect the CRM to other systems you already use (ERP, e-commerce, invoicing)?</li><li>Are you paying for features you don&#039;t use, or are you missing features you need every day?</li><li>Do you expect to grow and worry that the current solution will soon become a bottleneck?</li></ul><p class="wp-block-paragraph">If most of your answers reveal constraints and compromises, that&#039;s a signal that a standard solution might not be enough. Conversely, if your processes are straightforward and common, an off-the-shelf product is often the fastest and most cost-effective choice.</p><blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow"><p>The right question isn&#039;t &quot;what&#039;s the best CRM&quot;, but &quot;what&#039;s the right CRM for how my company works&quot;.</p></blockquote><p class="wp-block-paragraph">When processes are truly specific, evaluating custom development in a cloud environment gives you a tool that follows your rules, accessible from anywhere and designed to evolve alongside your business. It&#039;s in this scenario that our development and cloud services become an option to put on the table, alongside ready-made solutions, to choose with confidence.</p><h2 class="wp-block-heading">The limitations of standard CRM systems for small and medium-sized businesses</h2><p class="wp-block-paragraph">Off-the-shelf CRM platforms are built to satisfy as many companies as possible. Precisely because of this, they often end up not truly fitting anyone. For an SMB with established processes and a specific way of working, this &quot;one-size-fits-all&quot; approach translates into a series of daily frictions that slow down the team instead of supporting it.</p><p class="wp-block-paragraph">The first problem is feature overload. Many platforms offer dozens of modules designed for large enterprises: complex marketing automations, elaborate sales hierarchies, dashboards that no one actually uses. The result is a cluttered interface that lengthens training time and discourages adoption by team members.</p><p class="wp-block-paragraph">The second issue is rigid workflow structure. The software imposes its own workflow and expects the company to adapt, when it should be the other way around. If your sales cycle, quote management, or handoff procedures between departments follow a particular logic, you&#039;ll find yourself forcing data into fields and statuses that don&#039;t truly represent them.</p><ul class="wp-block-list"><li>Recurring license costs that grow with the number of users and &quot;premium&quot; features, regardless of whether you actually use them</li><li>Missing or limited integrations with your ERP, billing system, e-commerce platform, or existing tools, forcing duplicate data entry and misaligned records</li><li>Superficial customizations: you can change a few labels, but not the underlying logic that really matters</li><li>Vendor lock-in, where the provider decides the timing, pricing, and future of the platform on your behalf</li></ul><p class="wp-block-paragraph">Combined, these limitations carry a real cost: wasted time, unreliable data, and a monthly investment that never stops. This is where a solution built around your actual needs starts to make sense, because it starts from your real processes rather than imposing foreign ones.</p><p class="wp-block-paragraph">With custom development and cloud infrastructure, your customer management system can be designed around the way you actually work and delivered reliably wherever you need it, without carrying the burden of features you&#039;ll never use.</p><h2 class="wp-block-heading">When Custom CRM Development Makes Sense</h2><p class="wp-block-paragraph">Custom-built solutions aren&#039;t always the best choice: sometimes an off-the-shelf platform covers your needs well and lets you get started right away. The right question isn&#039;t &quot;which CRM is the best&quot;, but &quot;how far do my processes deviate from the standard&quot;. The more your company&#039;s way of working is unique and difficult to change, the more a CRM built around your actual requirements justifies the investment. Here are the concrete criteria to evaluate.</p><ul class="wp-block-list"><li>Specific business processes: if your sales cycle follows steps, roles, or rules that no off-the-shelf software reflects, adapting a standard tool creates constant compromises. A custom CRM shapes itself to your workflow, not the other way around.</li><li>Integration with existing accounting and ERP systems: when customer data, orders, invoicing, or inventory already live in other systems, the real priority is making them communicate. If off-the-shelf solutions offer only partial or rigid connectors, custom development enables clean integration without duplicate data entry.</li><li>Volume and complexity of data: large amounts of information, detailed historical records, or unique data structures can challenge standard systems, both in performance and in costs that grow per user or volume.</li><li>Automation needs: if you want to automate recurring tasks, reminders, assignments, or reports based on your own logic, and pre-built automations aren&#039;t enough, customization becomes a measurable operational advantage.</li></ul><p class="wp-block-paragraph">A practical way to decide: list the tasks you currently do by hand, outside your software, because no existing tool handles them. If this list is long and weighs on your team&#039;s daily workload, custom development deserves serious consideration. If it&#039;s just a few exceptions, a well-configured off-the-shelf solution is probably more efficient.</p><blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow"><p>Custom development makes sense when the cost of daily compromises exceeds the cost of building the right tool.</p></blockquote><p class="wp-block-paragraph">From a technical perspective, a project like this requires development expertise and reliable infrastructure: our development and cloud services are designed precisely to guide SMBs through this journey, from design to operation. If you want to dive deeper into the logic, timelines, and approach of a custom-built project, you&#039;ll find an in-depth discussion in our dedicated article on custom software development.</p><h2 class="wp-block-heading">Automation and integrations: making CRM the hub of business processes</h2><p class="wp-block-paragraph">A customized CRM performs best when it stops being a simple contact database and becomes the connection point between daily company activities. The difference isn&#039;t just in storing data, but in making it flow across departments and reducing the manual work that slows down sales, administration, and after-sales teams.</p><p class="wp-block-paragraph">The first concrete advantage is automating repetitive tasks. Many operations that today consume hours of work can be handled by the system without human intervention, with fewer errors and faster response times to customers.</p><ul class="wp-block-list"><li>Scheduled follow-ups: automatic reminders and emails to prospects who haven&#039;t responded in days, so no lead gets overlooked.</li><li>Automated reporting: dashboards and regular reports generated and sent to managers without manual data extraction.</li><li>Guided sales flows: opportunity status updates, lead assignment to the right salesperson, internal notifications when a deal progresses.</li><li>Deadline management: renewals, pending quotes, payment reminders flagged automatically.</li></ul><p class="wp-block-paragraph">The second advantage concerns integrations. A personalized CRM can communicate with the tools you already use daily: accounting software, billing systems, email, e-commerce, or support portals. This way, information entered once is available everywhere it&#039;s needed, without duplicate entries and without misaligned data across different software.</p><blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow"><p>Data entered once and usable by all departments: this is the sign that CRM has become the center of operations, not just another tool to update manually.</p></blockquote><p class="wp-block-paragraph">It&#039;s precisely here that custom development shows its value compared to off-the-shelf solutions: automations and integrations are built around how you actually work, not the other way around. Through development and cloud services, these connections can be implemented in a scalable way, keeping data accessible from multiple locations and ready to grow with your business.</p><p class="wp-block-paragraph">If you want to dive deeper into how to tackle the manual activities that consume the most time, this connects directly to our article on process automation for SMBs, where we analyze typical workflows to optimize before even choosing the tools.</p><h2 class="wp-block-heading">Costs, timelines and key factors in a custom CRM project</h2><p class="wp-block-paragraph">Anyone considering a custom CRM naturally asks two legitimate questions: how much does it cost and how long does it take? There&#039;s no one-size-fits-all answer, because the price and timeline depend on concrete choices regarding the complexity of the processes to be managed and the desired level of customization. Understanding these variables helps set realistic expectations and prepare a targeted quote request, avoiding surprises down the road.</p><p class="wp-block-paragraph">The first factor affecting costs is the initial analysis phase. Before writing a single line of code, you need to map workflows, define who will use the tool, and establish which data is truly valuable. A thorough analysis phase reduces subsequent errors and effectively controls overall costs: it&#039;s an investment, not a line item to cut corners on.</p><p class="wp-block-paragraph">The second element is the scope of functionality. A CRM that only handles contacts and sales opportunities has very different timelines and costs than one that includes quotes, advanced reporting, or post-sale management. Integrations with existing systems also impact the quote: the more data sources that need to be connected, the more development and testing work is required.</p><ul class="wp-block-list"><li>Analysis and process definition: the foundation on which the entire project is built.</li><li>Number and complexity of required features.</li><li>Integrations with accounting software, email, or other business tools.</li><li>Migration of existing data to the new system.</li><li>User training and support during the initial weeks.</li></ul><p class="wp-block-paragraph">Maintenance also needs to be considered, and it&#039;s often overlooked. Software evolves over time: it requires updates, fixes, and incremental improvements as your business grows. Planning a recurring budget for support from the start prevents the tool from becoming outdated or difficult to manage. Choosing to host the system in the cloud also matters, as it shifts costs from an upfront investment to a more predictable and scalable recurring expense.</p><p class="wp-block-paragraph">Our development and cloud services are designed specifically to guide SMEs through these phases, from analysis to implementation to ongoing management. The best way to get concrete figures is to start with a precise description of your needs: the clearer your starting point, the more reliable your quote will be.</p><h2 class="wp-block-heading">How RENOR &amp; Partners Supports SMEs in CRM Development</h2><p class="wp-block-paragraph">Undertaking a custom CRM project means making a series of technical and organizational decisions that, for companies without strong IT infrastructure, can be difficult to manage on their own. That&#039;s where we come in: translating your real business needs into a working solution, without requiring you to become a technology expert.</p><p class="wp-block-paragraph">Through our Development and Cloud service, we guide SMEs through the entire journey, from understanding current processes to deploying the system into production. Our goal isn&#039;t to hand over software and disappear, but to build a platform together that reflects how you actually work and can scale as your business grows.</p><p class="wp-block-paragraph">Our working approach is structured in clear phases, designed to give you visibility and control every step of the way:</p><ul class="wp-block-list"><li>Initial analysis: we start by listening to your sales and operational processes, to understand what you really need and where a CRM can deliver value.</li><li>Collaborative design: we define features, priorities, and timelines together, so your investment focuses on what matters most.</li><li>Custom development: we build the solution tailored to your needs, avoiding unnecessary features and added complexity.</li><li>Cloud deployment: we provide a reliable and accessible infrastructure, so you don&#039;t have to manage servers or systems internally.</li><li>Ongoing support: we stay with you beyond launch to adapt the tool as your business evolves.</li></ul><p class="wp-block-paragraph">Working with a single partner for development and cloud means having one accountable contact for your results, reducing coordination time and the risk of miscommunication. For a business owner or manager focused on running their operations, this continuity often makes the difference between a stalled project and one that truly gains traction.</p><blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow"><p>A good CRM doesn&#039;t come from a catalog of features, but from understanding how your company actually works.</p></blockquote><p class="wp-block-paragraph">If you&#039;re considering whether and how to implement a custom CRM, the first step requires no commitment: an initial consultation lets us review your situation and recommend the best path forward, including cost and priority considerations. Contact RENOR &amp; Partners to schedule a first conversation and discover together whether custom development is the right choice for your business.</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>Need concrete support?</strong> Discover our <a href="https://renor.it/en/services/development-and-cloud/">Development and cloud</a> service or <a href="https://renor.it/en/contact-us/">contact us</a> for a consultation.</p></div></div><p>L'articolo <a href="https://renor.it/en/blog/sviluppo-software-programmazione/custom-crm-development-for-smes/">Custom CRM Development for SMEs: When It&#8217;s Worth It and What to Consider</a> proviene da <a href="https://renor.it/en/">RENOR &amp; Partners S.r.l.</a>.</p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Software House for Custom ERP Solutions in Italy: Selection Guide</title>
		<link>https://renor.it/en/blog/sviluppo-software-programmazione/software-house-custom-erp-development-italy/</link>
		
		<dc:creator><![CDATA[Simone Renzi]]></dc:creator>
		<pubDate>Tue, 01 Sep 2026 10:43:58 +0000</pubDate>
				<category><![CDATA[Software Development & Programming]]></category>
		<category><![CDATA[automation]]></category>
		<category><![CDATA[digital transformation]]></category>
		<category><![CDATA[innovation]]></category>
		<category><![CDATA[renor]]></category>
		<guid isPermaLink="false">https://renor.it/blog/sviluppo-software-programmazione/software-house-custom-erp-development-italy/</guid>

					<description><![CDATA[<p>Discover how to choose the best software house to develop your custom ERP system in Italy. Complete guide and practical tips for businesses seeking</p>
<p>L'articolo <a href="https://renor.it/en/blog/sviluppo-software-programmazione/software-house-custom-erp-development-italy/">Software House for Custom ERP Solutions in Italy: Selection Guide</a> proviene da <a href="https://renor.it/en/">RENOR &amp; Partners S.r.l.</a>.</p>
]]></description>
										<content:encoded><![CDATA[<h2 class="wp-block-heading">Off-the-shelf or custom management software: when tailor-made solutions actually pay off</h2><p class="wp-block-paragraph">An off-the-shelf management solution is often the starting choice: it costs little upfront, launches quickly, and covers common needs like invoicing, inventory, and accounting. For many companies it&#039;s more than enough. The problem emerges when your workflows don&#039;t fit the software&#039;s standard templates: at that point, you end up adapting to the tool, rather than the other way around.</p><p class="wp-block-paragraph">The first red flag is exactly this: if your team wastes time on manual steps, parallel spreadsheets, or &quot;workarounds&quot; to make the software do what you actually need, it means the tool doesn&#039;t truly follow your workflow. These are hidden hours that, added up over a year, cost far more than it seems.</p><p class="wp-block-paragraph">The second red flag concerns integrations. A management system that doesn&#039;t connect with your e-commerce platform, your CRM, or your suppliers&#039; systems creates duplicate data entry, errors, and misaligned information. If you find yourself copying data from one program to another, the cost isn&#039;t just lost time—it&#039;s the risk of making decisions based on wrong numbers.</p><p class="wp-block-paragraph">The third red flag is financial. Off-the-shelf management systems charge licenses that grow with the number of users, add-on modules, and &quot;premium&quot; features. It&#039;s worth doing an honest calculation:</p><ul class="wp-block-list"><li>How much will you pay in licenses and subscriptions over the next three to five years?</li><li>How many features do you pay for but never use, and how many are missing?</li><li>What do the manual tasks that the software doesn&#039;t automate really cost you?</li></ul><p class="wp-block-paragraph">When your answers start worrying you, custom-built software stops being a luxury and becomes a rational investment. A tailored management system models exact functions to your processes, integrates the tools you already use, and eliminates licensing costs for unnecessary features. With custom development and cloud infrastructure, the solution grows with your business, staying accessible anywhere and adaptable over time.</p><blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow"><p>The right question isn&#039;t &quot;how much does custom software cost&quot;, but &quot;how much is it already costing me to keep adapting to a standard solution that doesn&#039;t fit my needs&quot;.</p></blockquote><h2 class="wp-block-heading">What a software house does in developing a custom management system</h2><p class="wp-block-paragraph">Partnering with a software house means activating a structured approach, not simply &quot;having someone write code&quot;. The value of a solid partner lies precisely in the methodology: every phase is designed to minimize risks and ensure that the management system truly reflects how your business operates. Here are the main activities involved.</p><ul class="wp-block-list"><li>Process analysis: before writing a single line of code, the workflow, critical points, and concrete objectives are studied. This is where real needs emerge, often different from those perceived initially.</li><li>Design: the architecture, priority features, and user experience are defined, providing a clear roadmap before development and realistic estimates of timelines and costs.</li><li>Development: the software is built in phases, with intermediate releases that allow testing and course correction without waiting for the project to finish.</li><li>Integration with existing systems: the management system connects with tools already in use (accounting, e-commerce, inventory) preventing duplicate data entry and scattered information.</li><li>Maintenance and evolution: after launch, the work continues with updates, fixes, and new features that grow alongside your business.</li></ul><p class="wp-block-paragraph">This is where the difference between a structured software house and an improvised freelancer becomes apparent. A solo professional can deliver solid projects, but rarely guarantees continuity: if they become unreachable, the management system risks being stuck with no one who understands it. A team, conversely, distributes expertise and ensures ongoing support, documentation, and the ability to address multiple areas.</p><p class="wp-block-paragraph">Another decisive element is the development and cloud component: building the management system with reliable infrastructure allows access from multiple locations and devices, with data always available and up-to-date. This translates into greater operational continuity and software that grows with your business, without constraints tied to a single workstation.</p><blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow"><p>A good custom management system isn&#039;t born from code, but from a deep understanding of how your business truly operates.</p></blockquote><h2 class="wp-block-heading">How to choose the right software company in Italy: criteria and questions to ask</h2><p class="wp-block-paragraph">Selecting the partner for your custom management system is a decision that will impact your business operations for years to come. It&#039;s not just about comparing quotes, but about evaluating reliability, expertise, and transparency. Below is a practical checklist to guide your decision and help you ask the right questions from your very first meeting.</p><h2 class="wp-block-heading">Essential evaluation criteria</h2><ul class="wp-block-list"><li>Cloud expertise: verify that the software company develops solutions designed for the cloud, which guarantee accessibility from multiple locations, scalability, and reduced dependence on physical servers to maintain in-house.</li><li>References and real-world cases: ask for examples of projects completed in industries similar to yours. A solid partner won&#039;t hesitate to showcase results and connect you with existing clients.</li><li>Work methodology: understand how they organize the project. Incremental releases and frequent reviews allow you to adjust course before it&#039;s too late, avoiding surprises at final delivery.</li><li>Post-release support: software doesn&#039;t end at delivery. Find out about response times, support channels, and how updates are managed over time.</li><li>Code ownership: clarify from the start who owns the source code. This is crucial to avoid being locked into a single vendor in the future.</li></ul><h2 class="wp-block-heading">Questions to ask at your first meeting</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><ul class="wp-block-list"><li>How do you manage project phases and how often will you update me on progress?</li><li>Will the software be hosted in the cloud and how do you guarantee service availability?</li><li>What happens if I want to switch vendors in the future or manage the code in-house?</li><li>What guarantees do you offer for post-release support and what are the associated costs?</li><li>Can you show me similar projects already in production?</li></ul><p class="wp-block-paragraph">A partner who answers these questions clearly demonstrates transparency and maturity. From this perspective, a development and cloud-oriented approach is a good starting point: it allows you to build a custom management system that&#039;s accessible and designed to grow alongside your business.</p><blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow"><p>The right software company isn&#039;t the one that promises the most, but the one that best explains how it works and what remains in your hands when the project is complete.</p></blockquote><h2 class="wp-block-heading">The phases of a customized business solution project: from analysis to launch</h2><p class="wp-block-paragraph">A tailor-made business solution doesn&#039;t start with writing code, but with understanding how you work. Learning the typical phases of the journey helps you know what to expect, set realistic timelines, and stay in control of your investment every step of the way.</p><ul class="wp-block-list"><li>Requirements analysis and gathering: business processes, roles, and data flows are mapped out. This is when you translate what you do every day into clear specifications, identifying priorities and constraints.</li><li>Prototype: before development starts, a clickable mockup of the main screens is built. It lets you &#039;see&#039; the solution and correct course when changes are still cheap to make.</li><li>Iterative development: the software is built module by module, released and tested in small increments. At each cycle you can evaluate concrete results, without waiting months for a single big release.</li><li>Testing: functionality, security, and edge cases are checked, and the people who&#039;ll use the tool in the field are involved to uncover errors and inconsistencies before launch.</li><li>Training: your team is guided through day-to-day use, with supporting materials. An effective business solution is one your team adopts without friction.</li><li>Go-live: the rollout to production happens in a controlled way, often with a support period during the first operational days to handle issues and respond quickly.</li></ul><p class="wp-block-paragraph">This approach reduces risk precisely because it spreads verification throughout the project rather than cramming it at the end. Decisions are made on tangible elements, and any corrections are handled when they&#039;re still simple and cost-effective to manage.</p><p class="wp-block-paragraph">One often overlooked aspect involves the infrastructure where your business solution lives. With a development and cloud service, the application is released in an accessible, maintainable environment, so you can focus on daily operations without managing the technical complexity yourself.</p><blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow"><p>A well-run project isn&#039;t one without surprises—it&#039;s one where surprises surface early and are resolved methodically.</p></blockquote><p class="wp-block-paragraph">Always ask the software vendor how they structure these phases and what verification points they include: the answer will tell you a lot about their transparency and professionalism.</p><h2 class="wp-block-heading">Cloud, integrations, and security: what to consider beyond features</h2><p class="wp-block-paragraph">When evaluating a custom enterprise system, the focus almost always falls on features: what the software does, which processes it automates, which reports it generates. These are important aspects, but not the only ones. There are three elements that often take a backseat yet determine over time whether your investment will continue to deliver value or become a burden: cloud scalability, the ability to integrate with systems you already use, and data protection.</p><h2 class="wp-block-heading">Scalability: growing without starting from scratch</h2><p class="wp-block-paragraph">A well-designed cloud infrastructure allows the system to adapt to your company&#039;s pace. If your users, orders, or connected branches double, the system must handle the load without slowdowns and without forcing you into costly migrations. Always ask how capacity increases are managed and what costs come with growth: a clear answer today saves you surprises tomorrow.</p><h2 class="wp-block-heading">Integrations: your system doesn&#039;t work alone</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">The new software will rarely replace everything you have. More often it will need to communicate with your accounting ERP, sales CRM, e-commerce platform, or invoicing tools. An enterprise system that automatically exchanges data with these platforms eliminates duplicate entries and reduces errors. Check whether the software vendor designs for integration from the start, rather than as a patch applied later.</p><ul class="wp-block-list"><li>Which existing systems will the software need to connect with?</li><li>Are data synchronized in real-time or at intervals?</li><li>What happens if you change one of the connected systems in the future?</li></ul><h2 class="wp-block-heading">Security: a requirement, not an add-on</h2><p class="wp-block-paragraph">Business data is an asset: customer information, price lists, contracts. Their protection must be built in during the design phase, with regular backups, access controls, and compliance with privacy regulations. It&#039;s not a technical detail to delegate, but a commitment of responsibility to your customers and your business.</p><p class="wp-block-paragraph">It is precisely on this ground that a partner&#039;s strength is measured. Through RENOR&#039;s Development and cloud service, we tackle these three aspects together from the earliest stages of your project, so your system is built ready to scale, integrate, and protect your data from day one.</p><h2 class="wp-block-heading">Costs, timelines, and return on investment of a custom business management system</h2><p class="wp-block-paragraph">One of the most common questions before launching a project is: how much does it cost and how long does it take? The honest answer is that it depends on the actual complexity of the processes to be digitalized. A custom business management system doesn&#039;t have a fixed price list because it&#039;s not an off-the-shelf product, but a solution built around how you actually work. Understanding what drives the budget lets you plan without surprises.</p><p class="wp-block-paragraph">The factors that impact costs and timelines the most are few but critical:</p><ul class="wp-block-list"><li>The number and complexity of processes to cover (inventory, orders, production, invoicing).</li><li>Integrations with systems already in place, such as e-commerce, accounting, or third-party tools.</li><li>The number of users and the different roles and permissions to manage.</li><li>Security and infrastructure requirements, especially in cloud-based solutions.</li><li>The amount and quality of data to migrate from existing systems.</li></ul><p class="wp-block-paragraph">On the timeline front, a first working module might take just a few weeks, while a complete system develops over a span of several months. A phased release approach, which introduces the most critical features first, reduces risk and lets you start capturing value before the project is fully complete.</p><p class="wp-block-paragraph">Return on investment shouldn&#039;t be measured only against the initial cost, but against concrete benefits over time. Here are the most significant indicators to track:</p><ul class="wp-block-list"><li>Time saved by people on repetitive tasks that are now automated.</li><li>Reduction in manual errors, with fewer reworks and complaints.</li><li>Faster access to up-to-date data for better decision-making.</li><li>Lower costs for licenses and disconnected tools replaced by a single system.</li></ul><blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow"><p>A custom business management system pays for itself when the time it returns every month consistently exceeds what it costs to maintain.</p></blockquote><p class="wp-block-paragraph">To protect your investment over time, the technical development choices and cloud infrastructure also matter: a solid foundation and reliable infrastructure avoid hidden future costs and keep the system ready to grow with your business. Before you start, define with your partner which metrics you&#039;ll measure: it&#039;s the clearest way to justify the spend and verify, with data in hand, that the investment is delivering the expected results.</p><h2 class="wp-block-heading">Next step: talk to a partner about your custom management system</h2><p class="wp-block-paragraph">After assessing criteria, phases, costs, and technical aspects, the time comes for concrete decision-making. The most effective way to understand whether a tailored management system is the right choice for your business isn&#039;t to keep gathering abstract information, but to engage with those who design these systems every day, starting from your actual processes and goals.</p><p class="wp-block-paragraph">RENOR &amp; Partners is an Italian software house that supports businesses and organizations in developing customized solutions and managing them in the cloud. Working with a local partner means speaking the same language, understanding the regulatory and operational environment you operate in, and having a point of contact available when needed—not just during the sales phase but throughout the entire project lifecycle.</p><p class="wp-block-paragraph">An initial conversation helps clarify some practical aspects before even discussing development:</p><ul class="wp-block-list"><li>Which business processes are actually slowing you down and deserve to be digitized first</li><li>Whether a fully tailored approach makes sense or if a more standard solution might be enough, at least initially</li><li>How to structure the project to achieve concrete results in reasonable timeframes, without wasting resources</li><li>Which technical and organizational priorities to address to avoid finding yourself stuck six months down the line</li></ul><p class="wp-block-paragraph">At this stage, IT consulting and strategic consulting play a decisive role: they help translate business objectives into sustainable technological choices, defining what to build, in what order, and with what expected return. It&#039;s the best way to avoid misdirected investments and to create a system that grows alongside your company.</p><blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow"><p>A good management system isn&#039;t born from a quote—it&#039;s born from an honest conversation about your goals.</p></blockquote><p class="wp-block-paragraph">If you&#039;re evaluating a custom management system or simply want to figure out where to start, the advice is to book an introductory consultation. A single meeting and a description of your needs are enough to receive a concrete assessment, with no commitment, and turn the insights from this guide into a clear, tailored roadmap for your business.</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>Need concrete support?</strong> Discover our <a href="https://renor.it/en/services/development-and-cloud/">Development and cloud</a> service or <a href="https://renor.it/en/contact-us/">contact us</a> for a consultation.</p></div></div><p>L'articolo <a href="https://renor.it/en/blog/sviluppo-software-programmazione/software-house-custom-erp-development-italy/">Software House for Custom ERP Solutions in Italy: Selection Guide</a> proviene da <a href="https://renor.it/en/">RENOR &amp; Partners S.r.l.</a>.</p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Custom Software Development for Companies: When It&#8217;s Worth It and How Much It Costs</title>
		<link>https://renor.it/en/blog/sviluppo-software-programmazione/custom-software-development-for-companies/</link>
		
		<dc:creator><![CDATA[Simone Renzi]]></dc:creator>
		<pubDate>Mon, 31 Aug 2026 10:35:41 +0000</pubDate>
				<category><![CDATA[Software Development & Programming]]></category>
		<category><![CDATA[automation]]></category>
		<category><![CDATA[digital transformation]]></category>
		<category><![CDATA[innovation]]></category>
		<category><![CDATA[renor]]></category>
		<guid isPermaLink="false">https://renor.it/blog/sviluppo-software-programmazione/custom-software-development-for-companies/</guid>

					<description><![CDATA[<p>Discover when custom software development is right for your business. Analyze costs, benefits, and tailored solutions for your specific needs.</p>
<p>L'articolo <a href="https://renor.it/en/blog/sviluppo-software-programmazione/custom-software-development-for-companies/">Custom Software Development for Companies: When It&#8217;s Worth It and How Much It Costs</a> proviene da <a href="https://renor.it/en/">RENOR &amp; Partners S.r.l.</a>.</p>
]]></description>
										<content:encoded><![CDATA[<h2 class="wp-block-heading">Custom software or ready-made solution? How to figure out what you really need</h2><p class="wp-block-paragraph">&quot;Custom software&quot; refers to an application designed and built specifically for your company, tailored to your processes and workflows. A ready-made solution (or &quot;off-the-shelf&quot;), on the other hand, is a pre-packaged product designed to fit many different businesses: you use it as is, with at most a few configuration options. There&#039;s no universally better choice—it depends on whether your needs are common or unique.</p><p class="wp-block-paragraph">The right question to ask isn&#039;t &quot;which software has more features,&quot; but &quot;does my business operate like many others, or do I have characteristics that set me apart?&quot; If you handle invoicing, inventory, or accounting in a fairly standard way, a ready-made ERP solution covers your needs well, costs less, and is available right away. But if your processes are your competitive advantage, forcing them into a rigid tool risks slowing you down.</p><p class="wp-block-paragraph">There are some concrete signals that suggest when a custom solution is worth considering.</p><ul class="wp-block-list"><li>You rely on many spreadsheets and manual steps to work around the limitations of your current software.</li><li>Your programs don&#039;t communicate with each other and you have to re-enter the same data multiple times.</li><li>A key process in your business isn&#039;t covered by any standard product.</li><li>You pay for licenses for features you don&#039;t use, but you&#039;re missing exactly what you need.</li><li>You expect to grow and worry that your current tool won&#039;t handle higher volumes or new requirements.</li></ul><p class="wp-block-paragraph">If you recognize yourself in more than one of these points, a custom solution would likely save you time and reduce errors. In many cases, the smartest approach is hybrid: keep standard tools where they work well and develop custom solutions only for the parts that truly set you apart, integrating them together.</p><blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow"><p>The right software isn&#039;t the one with the most features, but the one that adapts to how you work instead of forcing you to change.</p></blockquote><p class="wp-block-paragraph">That&#039;s where our development and cloud services come in: we build the application around your processes and make it reliably accessible, so you can start with what you need today and grow the solution as your business evolves.</p><h2 class="wp-block-heading">Concrete business benefits: processes, competitiveness, and scalability</h2><p class="wp-block-paragraph">Software built around the way your business operates delivers measurable results from the first few months. The reason is straightforward: instead of forcing your people to adapt to a tool designed for someone else, the tool adapts to the processes that already create value. Let&#039;s look at where the most tangible benefits concentrate.</p><h2 class="wp-block-heading">Smoother processes and fewer manual errors</h2><p class="wp-block-paragraph">Many inefficiencies don&#039;t stem from lack of effort, but from repetitive tasks done by hand: data copied from one file to another, quality checks done from memory, handoffs between departments managed via email. Each manual step is a point where errors and delays can creep in. Custom-built software automates exactly these bottlenecks, cuts rework, and frees up your team to focus on higher-value activities.</p><ul class="wp-block-list"><li>Less time wasted on manual data entry and verification</li><li>Fewer errors that create hidden costs and customer complaints</li><li>Up-to-date information shared across departments, with no duplication</li></ul><h2 class="wp-block-heading">A competitive edge your rivals can&#039;t easily copy</h2><p class="wp-block-paragraph">When the software reflects your specific way of serving customers, that advantage becomes hard to replicate. Faster response times, more accurate quotes, complete traceability—these are things your customers notice and that set you apart. Unlike off-the-shelf solutions available to anyone, custom-built software embeds your know-how and works in your favor.</p><h2 class="wp-block-heading">Growth and scalability over time</h2><p class="wp-block-paragraph">A solid investment doesn&#039;t just solve today&#039;s problem—it grows alongside your business. Increasing volume, new locations, new services to manage without having to rebuild everything each time. This is where our Development and cloud approach comes in: we build the application around your specific needs and deploy it on a cloud infrastructure that scales resources with your actual growth, with no oversized fixed costs in the early stages.</p><blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow"><p>The value of custom software isn&#039;t measured only by what it does today, but by how it lets you grow tomorrow without starting from scratch.</p></blockquote><h2 class="wp-block-heading">The phases of a custom development project: from analysis to release</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">A custom development project is not improvised—it follows a structured path with clearly defined phases. Understanding these in advance lets you know what to expect, when your involvement will be needed, and how to keep control over timelines and budget. Here are the main stages.</p><ul class="wp-block-list"><li>Requirements analysis: it starts with your business goals and your company&#039;s actual processes. This phase involves gathering the needs of those who will use the software and turning them into clear requirements. This is the most critical moment: it&#039;s where you avoid misunderstandings that would be costly to fix later.</li><li>Design: it defines how the solution will be built, from technical architecture to user experience. Early sketches or prototypes of the screens are often created, so you can review and make corrections before a single line of actual code is written.</li><li>Development: this is when the software takes shape, typically progressing in successive increments. Working through progressive releases lets you see concrete results as you go, rather than waiting for the finished product without interim feedback.</li><li>Testing and QA: every feature is verified to ensure it meets the requirements and is reliable. Testing involves your team as well, as you try out the software under conditions close to real-world scenarios before it goes live.</li><li>Release and maintenance: the software is deployed and made available to users. From here begins an ongoing phase of updates, fixes, and improvements, because a custom business application evolves alongside your company.</li></ul><p class="wp-block-paragraph">An often overlooked aspect is where the software is hosted and run. Our development and cloud services let you manage the entire cycle, from building the application through to its operation in the cloud environment, so nothing falls through the cracks in that critical handoff between software development and daily use.</p><blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow"><p>The value of a custom project isn&#039;t measured just on release day, but in the ability to support your company over time, phase by phase.</p></blockquote><h2 class="wp-block-heading">Integration with the systems you already use: ERP platforms, management software and external tools</h2><p class="wp-block-paragraph">Custom software rarely comes into existence in a vacuum. In most companies, there&#039;s already an ecosystem of tools in place: the management system that handles orders and inventory, the ERP that brings accounting and production together, the CRM for customers, the e-commerce platform, the courier portal. The value of a new solution depends in large part on its ability to work seamlessly with these systems, avoiding data silos and duplicate data entry.</p><p class="wp-block-paragraph">The principle is straightforward: data should be entered only once and then automatically flow wherever it&#039;s needed. When integration works well, an order received online updates the warehouse, generates accounting records, and notifies logistics without any manual intervention. When systems remain isolated, staff spend hours retyping information, with a real risk of errors and delays.</p><p class="wp-block-paragraph">From a technical standpoint, integration is achieved primarily through APIs—the channels through which two applications exchange data in a structured way. Feasibility and complexity depend on how &quot;open&quot; your existing software is: some modern management systems offer ready-made connections, while older ones require middleware solutions. This is something to evaluate early on, during the analysis phase, because it significantly impacts timelines and budget.</p><blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow"><p>Before building something new, always ask yourself: which systems will it need to communicate with, and are those systems capable of doing so?</p></blockquote><p class="wp-block-paragraph">This is where a partner with development and cloud expertise makes a real difference: designing infrastructure in the cloud allows you to link multiple applications reliably, to scale data flows as volumes grow, and to ensure that data exchange is continuous and secure. This is the approach we follow to build solutions that integrate into your existing ecosystem, rather than replace it entirely.</p><p class="wp-block-paragraph">Two points are worth considering before moving forward:</p><ul class="wp-block-list"><li>Integration costs deserve their own discussion: we&#039;ll cover them later, because they can be as significant as development itself.</li><li>Once your systems are connected, the path opens to process automation and artificial intelligence—natural evolutions when data is already organized and available in a single flow.</li></ul><h2 class="wp-block-heading">How much does custom software development cost: factors that impact your quote</h2><p class="wp-block-paragraph">Asking &quot;how much does custom software cost&quot; is like asking how much a house costs: it depends on the size, materials, and what it needs to do. That&#039;s why finding a reliable price list online is nearly impossible. Be skeptical of anyone who quotes a price before fully understanding the problem you need to solve. However, there are concrete factors that shift the budget, and knowing them helps you evaluate proposals critically.</p><ul class="wp-block-list"><li>Functional complexity: how many tasks the software must perform and how intricate the workflows are. A management tool that automates a few steps costs far less than a platform that coordinates multiple departments, roles, and business rules.</li><li>Integrations: connecting to management systems, ERPs, e-commerce platforms, or external tools requires time for analysis and development. The more systems that need to communicate, the greater the effort, especially when the existing software is outdated or poorly documented.</li><li>Number of users and workload: an application used by five people has different requirements than one that must handle thousands of simultaneous access requests without slowdowns.</li><li>Design and usability: well-crafted interfaces designed to minimize errors and training time require additional investment that often pays for itself in improved productivity.</li><li>Security and regulatory requirements: managing sensitive data or meeting specific industry compliance obligations increases the necessary work.</li></ul><p class="wp-block-paragraph">One aspect many overlook is maintenance. Software isn&#039;t a one-time purchase: it needs updates, bug fixes, and adjustments as business needs and regulations change. Infrastructure also impacts ongoing costs. With a cloud-based development approach, for example, you can scale resources based on actual usage, avoiding upfront payments for capacity you might never use.</p><blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow"><p>The most useful quote isn&#039;t the lowest—it&#039;s the one that clearly explains what you&#039;re paying for and why.</p></blockquote><p class="wp-block-paragraph">The most practical way to get a realistic estimate is to start by comparing your goals and the systems you already use. Tell us about the process you want to improve: we can help you define priorities, potential solutions, and a quote built on your real numbers, not generic figures.</p><h2 class="wp-block-heading">How to choose the right partner and request a consultation</h2><p class="wp-block-paragraph">After clarifying your needs, benefits, phases, and costs, comes the most important decision: who to entrust with the project. A supplier&#039;s quality impacts the outcome just as much as your budget. A competent partner reduces risks, prevents delays, and builds a solution that grows with your business, rather than becoming a constraint that needs to be redone in a few years.</p><p class="wp-block-paragraph">When evaluating a potential supplier, don&#039;t stop at the lowest quote. Focus on concrete factors that say a lot about the seriousness of their work.</p><ul class="wp-block-list"><li>Proven experience: ask for real cases, references, and projects similar to yours in terms of industry or complexity.</li><li>Clear working method: how analysis, development, testing, and deployment are managed, and the timelines involved.</li><li>Transparent communication: a good partner explains their choices in an understandable way, without hiding behind technical jargon.</li><li>Cloud management and maintenance: verify how continuity, security, and support are guaranteed after deployment.</li><li>Code and credential ownership: make sure you retain control of what belongs to you.</li></ul><p class="wp-block-paragraph">Another important signal is whether the supplier is willing to listen before proposing. Someone who jumps straight to a solution without understanding your processes will rarely build something that truly serves you. Initial consultation exists precisely for this: to focus on objectives, priorities, and constraints, so you arrive at a realistic proposal rather than a generic quote.</p><blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow"><p>The right partner isn&#039;t the one who always says yes, but the one who helps you understand what&#039;s actually worth doing.</p></blockquote><p class="wp-block-paragraph">With our Development and cloud service, we support companies from planning through to deployment of the solution, handling both custom development and the cloud infrastructure that hosts it. This allows you to have a single point of contact for the entire journey, with greater clarity on timelines and responsibilities.</p><p class="wp-block-paragraph">If you&#039;re evaluating a software project or want to understand whether it makes sense to move forward, request a consultation: we&#039;ll analyze your needs together and help you define the best approach, with no obligation.</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>Need concrete support?</strong> Discover our <a href="https://renor.it/en/services/development-and-cloud/">Development and cloud</a> service or <a href="https://renor.it/en/contact-us/">contact us</a> for a consultation.</p></div></div><p>L'articolo <a href="https://renor.it/en/blog/sviluppo-software-programmazione/custom-software-development-for-companies/">Custom Software Development for Companies: When It&#8217;s Worth It and How Much It Costs</a> proviene da <a href="https://renor.it/en/">RENOR &amp; Partners S.r.l.</a>.</p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>How much does it cost to develop a business mobile app? Price guide and key factors</title>
		<link>https://renor.it/en/blog/sviluppo-software-programmazione/mobile-app-development-cost-for-businesses/</link>
		
		<dc:creator><![CDATA[Simone Renzi]]></dc:creator>
		<pubDate>Mon, 13 Jul 2026 08:55:59 +0000</pubDate>
				<category><![CDATA[Software Development & Programming]]></category>
		<category><![CDATA[automation]]></category>
		<category><![CDATA[innovation]]></category>
		<category><![CDATA[renor]]></category>
		<category><![CDATA[technology]]></category>
		<guid isPermaLink="false">https://renor.it/blog/sviluppo-software-programmazione/mobile-app-development-cost-for-businesses/</guid>

					<description><![CDATA[<p>Discover the real costs to develop a business mobile app. Analyze pricing factors and plan your budget with confidence and clarity.</p>
<p>L'articolo <a href="https://renor.it/en/blog/sviluppo-software-programmazione/mobile-app-development-cost-for-businesses/">How much does it cost to develop a business mobile app? Price guide and key factors</a> proviene da <a href="https://renor.it/en/">RENOR &amp; Partners S.r.l.</a>.</p>
]]></description>
										<content:encoded><![CDATA[<h2 class="wp-block-heading">Why the right question isn&#039;t &quot;how much does it cost&quot; but &quot;what do you need&quot;</h2><p class="wp-block-paragraph">Asking how much a business app costs is like asking how much a vehicle costs: it depends on whether you need a scooter for city deliveries or a truck for hauling cargo over long distances. The price doesn&#039;t exist in the abstract—it takes shape only when the problem the app needs to solve becomes clear. This is why, before even discussing budget, it&#039;s worth shifting focus to your business objective.</p><p class="wp-block-paragraph">An app that digitizes an internal process for twenty employees has very different needs from an app aimed at thousands of end customers. The essential features change, the level of reliability required changes, data management changes, and the ability to handle usage spikes changes. These choices, driven by your goals, are what determine the cost—not a price list handed down from above.</p><p class="wp-block-paragraph">Starting from real needs also helps you avoid two opposite and very costly mistakes: paying for features you&#039;ll never use, or cutting corners on elements that will become bottlenecks the moment the app grows. That&#039;s why the most useful questions at the start are concrete ones:</p><ul class="wp-block-list"><li>What problem or task should the app simplify, and for whom?</li><li>Who will use it: employees, customers, suppliers? How many, and how often?</li><li>What measurable results do you expect in the first six to twelve months?</li><li>How do you envision usage growth over time?</li></ul><p class="wp-block-paragraph">The answers to these questions guide technical choices that would otherwise be invisible but are crucial to the cost—like development architecture and the cloud infrastructure the app will run on. A properly sized system lets you start with the essentials and scale when you need to, without rebuilding from scratch. That&#039;s the approach we take to development and cloud: not a quote drawn up before we know you, but a solution built around what your company actually wants to achieve.</p><blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow"><p>Price isn&#039;t the starting point: it&#039;s the result of good decisions based on your objectives.</p></blockquote><h2 class="wp-block-heading">The factors that determine the cost of a business app</h2><p class="wp-block-paragraph">A quote for an app is never a number pulled out of thin air: it&#039;s the sum of concrete choices about what you want to achieve and the context in which the application will operate. Understanding which variables affect the price allows you to read a proposal with a critical eye, compare different vendors, and figure out where you can cut costs without compromising results.</p><p class="wp-block-paragraph">Here are the items that weigh most heavily on a development budget:</p><ul class="wp-block-list"><li>Target platforms: developing for iOS, Android, and web means multiplying the work involved. Covering all channels ensures maximum reach, but if your users primarily rely on a single system, focusing on that one reduces initial costs.</li><li>Feature complexity: a screen that displays information costs far less than features like payment processing, real-time chat, geolocation, or personalized notifications. Each feature adds development and testing time.</li><li>Integration with your systems: connecting the app to your business management software, ERP, or CRM is often the trickiest part. It depends on how well those systems are set up to communicate externally, and it can significantly impact the quote.</li><li>Design and UX: a polished, intuitive interface that aligns with your company brand requires design work. It&#039;s not just a cosmetic cost: a confusing app gets abandoned, wasting the investment.</li><li>Backend and cloud: the part users never see. It&#039;s the infrastructure that manages data, users, and business logic. Its robustness and scalability determine how well the app will hold up over time and under load.</li><li>Security: protecting company and customer data involves technical safeguards and checks that need to be planned from the start, especially if you handle sensitive information.</li></ul><p class="wp-block-paragraph">Many of these items are interconnected: backend, cloud, and security, for instance, need to be designed together. This is where a partner capable of handling both application development and the cloud infrastructure it runs on makes a real difference, because it prevents decisions made in one area from creating unexpected costs in another.</p><blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow"><p>When you review a quote, always ask yourself which of these factors each line item refers to: it&#039;s the simplest way to understand what you&#039;re really paying for.</p></blockquote><h2 class="wp-block-heading">Indicative Price Ranges: From MVP to Enterprise App</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">A necessary disclaimer: every figure that follows is an order of magnitude, not a quote. The purpose is to help you understand which price bracket your idea falls into, so you can enter negotiations with realistic expectations. Costs vary based on the factors we&#039;ve already discussed (platforms, integrations, security, maintenance) and the supplier&#039;s target market.</p><p class="wp-block-paragraph">To guide you, we distinguish three recurring project types.</p><ul class="wp-block-list"><li>Simple App / MVP: an initial version with only essential features, designed to validate your idea in the market or address a specific need. Roughly €10,000–30,000. Little to no complex server-side logic, few integrations, minimal but polished interface.</li><li>Business Management App with Backend: manages data, users, and company processes, with a dedicated server, admin area, authentication, and some integrations (for example, payment processing or integration with existing business software). Roughly €30,000–80,000. This is the most common range for SMEs digitizing a workflow.</li><li>Complex Enterprise App: many features, detailed roles and permissions, integrations with multiple systems, high security and scalability requirements, often covering multiple platforms. From €80,000 and up, with no hard ceiling because it depends on the project&#039;s scope.</li></ul><p class="wp-block-paragraph">An often-overlooked aspect is infrastructure costs. A business management or enterprise app doesn&#039;t just live on the user&#039;s phone: it needs a reliable backend and a cloud environment sized for your user base and traffic peaks. This line item affects both initial development and monthly recurring costs, and should be evaluated from the start to avoid surprises.</p><blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow"><p>There&#039;s no list price: there&#039;s the price of your project, determined by what it needs to do and how long it needs to perform.</p></blockquote><p class="wp-block-paragraph">Our approach is to combine application development with the design of the cloud infrastructure that supports it, so that the estimate accounts for the full picture and not just the software the user sees. Before we provide an estimate, it&#039;s always worth clearly defining the scope: a clear request reduces uncertainty and makes the numbers far more reliable.</p><h2 class="wp-block-heading">Native, hybrid, or web app: how your tech choice impacts your budget</h2><p class="wp-block-paragraph">Behind every app lies a technical decision that affects your budget far more than you might think: the development approach. There&#039;s no single &quot;best&quot; choice, but rather the one that fits your specific goals. Understanding the differences enables you to work effectively with your development team and avoid overspending relative to your actual needs.</p><p class="wp-block-paragraph">There are three main paths: native development, hybrid (or cross-platform) development, and web apps. Each carries different implications for upfront costs, timelines, and ongoing maintenance expenses.</p><ul class="wp-block-list"><li>Native app: developed separately for iOS and Android using language-specific to each platform. It delivers the best performance and full access to device features (camera, notifications, sensors). It costs more because you&#039;re essentially building two distinct applications, which also doubles maintenance work down the line.</li><li>Hybrid or cross-platform app: a single codebase that runs on both operating systems. It significantly reduces development costs and time while simplifying updates, all while maintaining solid performance for most business use cases. It&#039;s often the sweet spot between quality and investment.</li><li>Web app: accessible through a browser with no app store installation needed. It&#039;s the most economical and fastest solution, ideal for internal management tools, but with limited access to device features and a less smooth mobile experience.</li></ul><p class="wp-block-paragraph">The often-overlooked factor is maintenance. A native app means two separate codebases to update with every new OS version: a recurring cost that, over time, can exceed the initial investment. The hybrid approach concentrates these updates into a single codebase, keeping long-term expenses in check.</p><blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow"><p>The deciding question isn&#039;t &quot;which technology is most powerful&quot;, but &quot;how much will it cost me to maintain this app in two years?&quot;</p></blockquote><p class="wp-block-paragraph">On top of this choice comes the infrastructure that powers your app: where data lives, how the service scales as your user base grows, how reliable it is. This is where development and cloud infrastructure work hand in hand: a well-thought-out architecture from the start prevents costly rewrites later and lets your app grow with your business without budget surprises.</p><h2 class="wp-block-heading">Hidden costs: maintenance, updates, and cloud</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">The development quote tells only part of the story. The day your app launches on the app stores doesn&#039;t mark the end of your investment—it marks the beginning of an ongoing expense that many companies discover too late. A mobile app isn&#039;t a turnkey project: it&#039;s a living product that needs ongoing care to keep working and delivering value.</p><p class="wp-block-paragraph">Several line items tend to slip through initial planning and, when combined, significantly impact your real costs over time.</p><ul class="wp-block-list"><li>Cloud hosting and infrastructure: most apps rely on a backend that needs to stay available around the clock. This cost grows with your user base and the amount of data being managed.</li><li>Operating system updates: Apple and Google release new versions of iOS and Android every year. Without regular updates, your app risks becoming broken or being delisted from the stores.</li><li>Store account fees: Apple and Google developer accounts require annual fees to keep your app published.</li><li>Security and bug fixes: you need to address bugs reported by users and keep libraries updated to patch vulnerabilities, protecting both your business data and your customers&#039; information.</li></ul><p class="wp-block-paragraph">A realistic estimate: annual maintenance costs typically fall between 15% and 20% of your initial development budget. Overlooking this expense means building on a foundation destined to crumble.</p><blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow"><p>An outdated app isn&#039;t a frozen investment: it&#039;s an investment losing value every month.</p></blockquote><p class="wp-block-paragraph">That&#039;s why choosing a vendor requires looking beyond handoff. You need a partner who can support your app over time, from development through managing the infrastructure it runs on. That&#039;s exactly what our development and cloud service does: we follow your product continuously, so every update, fix, and adjustment becomes part of a planned roadmap rather than a last-minute emergency.</p><h2 class="wp-block-heading">How to Get a Custom Quote and Reduce Project Risks</h2><p class="wp-block-paragraph">Getting to a reliable quote doesn&#039;t mean asking the first vendor you find to throw a number at you—it means putting the vendor in a position to truly understand what you need. The clearer your initial picture, the more realistic the estimate and the fewer surprises you&#039;ll encounter along the way. The difference between a project that stays on budget and schedule versus one that spirals out of control almost always comes down to those first few weeks.</p><p class="wp-block-paragraph">The first concrete step is to gather and document your requirements in writing. You don&#039;t need a technical document: just clear answers to a few fundamental questions that you can prepare internally before even speaking with a partner.</p><ul class="wp-block-list"><li>What problem does the app need to solve and for whom (customers, employees, sales teams)?</li><li>What are the 3–5 must-have features for launch and which ones can wait?</li><li>What existing systems will need to talk to the app (ERP, CRM, e-commerce)?</li><li>What user and data volumes do you expect in the first 12–18 months?</li><li>What&#039;s your ballpark budget and the target date for the app to go live?</li></ul><p class="wp-block-paragraph">With these elements in hand, the second step is a feasibility analysis. It&#039;s a short but critical phase: it validates your technical assumptions, produces a credible effort estimate, and surfaces risks before they become costs. Starting with a well-defined MVP, as we saw in the pricing tiers, and with cloud infrastructure sized to your actual needs lets you spread your investment over time instead of betting everything on a single initial push.</p><blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow"><p>A custom quote isn&#039;t necessarily a cheaper quote—it&#039;s a quote where you know exactly what you&#039;re paying for.</p></blockquote><p class="wp-block-paragraph">The third step is to partner with someone who can guide you from idea through production. RENOR &amp; Partners&#039; Development and Cloud Services exist precisely to combine application design with infrastructure management, bringing a strategic consulting approach that starts with your business goals rather than a pre-packaged solution.</p><p class="wp-block-paragraph">If you&#039;re evaluating an enterprise app, the most effective way to turn this article&#039;s estimates into concrete numbers is to talk with us: we start with your requirements, translate them into a feasibility analysis, and deliver a clear roadmap with defined costs and priorities.</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>Need concrete support?</strong> Discover our <a href="https://renor.it/en/services/development-and-cloud/">Development and cloud</a> service or <a href="https://renor.it/en/contact-us/">contact us</a> for a consultation.</p></div></div><p>L'articolo <a href="https://renor.it/en/blog/sviluppo-software-programmazione/mobile-app-development-cost-for-businesses/">How much does it cost to develop a business mobile app? Price guide and key factors</a> proviene da <a href="https://renor.it/en/">RENOR &amp; Partners S.r.l.</a>.</p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Customized ERP Software Quote: Cost Guide for Businesses</title>
		<link>https://renor.it/en/blog/sviluppo-software-programmazione/customized-erp-software-quote-pricing-businesses/</link>
		
		<dc:creator><![CDATA[Simone Renzi]]></dc:creator>
		<pubDate>Sun, 12 Jul 2026 09:08:31 +0000</pubDate>
				<category><![CDATA[Software Development & Programming]]></category>
		<category><![CDATA[automation]]></category>
		<category><![CDATA[ERP software]]></category>
		<category><![CDATA[innovation]]></category>
		<category><![CDATA[renor]]></category>
		<guid isPermaLink="false">https://renor.it/blog/sviluppo-software-programmazione/customized-erp-software-quote-pricing-businesses/</guid>

					<description><![CDATA[<p>Discover real costs for customized ERP software for your business. Complete guide to quotes and tailored solutions available for enterprises.</p>
<p>L'articolo <a href="https://renor.it/en/blog/sviluppo-software-programmazione/customized-erp-software-quote-pricing-businesses/">Customized ERP Software Quote: Cost Guide for Businesses</a> proviene da <a href="https://renor.it/en/">RENOR &amp; Partners S.r.l.</a>.</p>
]]></description>
										<content:encoded><![CDATA[<h2 class="wp-block-heading">Custom management software or standard package: when bespoke makes sense</h2><p class="wp-block-paragraph">The first choice you need to make isn&#039;t about price, but about how well the solution aligns with the way your business actually operates. A standard management system (off-the-shelf) is a ready-made product available for purchase or subscription that covers needs common to most companies: accounting, inventory, invoicing, and customer records. A custom solution, on the other hand, is designed and built starting from your specific processes.</p><p class="wp-block-paragraph">The standard package has real advantages: lower upfront costs, quick implementation, and guaranteed updates and support from the vendor. The catch is that it requires you to adapt to the software, not the other way around. As long as your processes fit the system&#039;s framework, it works well. But when you start accumulating parallel spreadsheets, manual workarounds, and &#039;tricks&#039; to make things balance, you&#039;re already paying a hidden cost.</p><p class="wp-block-paragraph">Custom solutions make sense when customization isn&#039;t a whim, but a competitive advantage. Here are the clearest signs:</p><ul class="wp-block-list"><li>You have unique workflows that no standard package can handle without compromises.</li><li>You&#039;re already using multiple programs that don&#039;t communicate with each other and you want a single source of truth for your data.</li><li>You anticipate growth or frequent changes and need a tool that evolves with your business.</li><li>The way you work is part of the value you deliver to customers and you don&#039;t want to flatten it into a standard model.</li></ul><p class="wp-block-paragraph">Conversely, if your processes are straightforward and typical for your industry, an off-the-shelf product is often the most practical choice: requesting a custom quote wouldn&#039;t make much sense. There&#039;s a middle ground that&#039;s quite common: start with a solid foundation and customize only the parts that truly make a difference.</p><p class="wp-block-paragraph">This is where a development partner comes in. Through development services and cloud infrastructure, you can build a management system tailored to your processes and made accessible at scale, so the tool grows alongside your business without having to start over every time something changes.</p><blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow"><p>The right question isn&#039;t &#039;how much does custom cost&#039;, but &#039;how much am I spending by forcing my business to fit a tool that doesn&#039;t represent it&#039;.</p></blockquote><h2 class="wp-block-heading">What factors determine the cost of a custom management software</h2><p class="wp-block-paragraph">When requesting a quote for personalized management software, the first question is almost always the same: &quot;How much does it cost?&quot;. The honest answer is that the price isn&#039;t a fixed number, but rather the result of several concrete variables. Understanding what they are helps you read an offer with a critical eye and distinguish a serious quote from a hasty one.</p><p class="wp-block-paragraph">Here are the factors that have the greatest impact on your final investment:</p><ul class="wp-block-list"><li>Number of modules and features: a management system that only covers invoicing costs very differently from one that also handles inventory, sales, production, and reporting. The more areas covered, the more development time needed.</li><li>Integrations with existing systems: connecting the new software to tools already in use (accounting, e-commerce, third-party management systems, shipping systems) requires dedicated technical work. Each integration must be designed and tested.</li><li>Number and type of users: how many people will use the management software and with what permissions. Managing different roles, differentiated access levels, and multiple concurrent users increases complexity.</li><li>Complexity of business processes: a linear workflow translates into leaner development. Processes with many exceptions, multi-level approvals, or special rules require more thorough analysis.</li><li>Specific customizations: custom interfaces, particular calculations, documents generated according to your needs. Each element &quot;tailored&quot; to your way of working carries weight in the quote.</li><li>Maintenance and support: the cost doesn&#039;t end at delivery. Updates, fixes, and ongoing support should be factored into your overall budget, often as a periodic fee.</li></ul><p class="wp-block-paragraph">Another element that affects costs is the software release approach. With a cloud development approach, the application is made available online: this impacts the cost structure, shifting part of the expense from an initial infrastructure investment to a more flexible and scalable model over time.</p><p class="wp-block-paragraph">The practical advice is to always request a quote that itemizes these elements separately. A transparent offer allows you to understand where you&#039;re investing, decide what to implement right away and what to defer to a later phase, keeping control over your budget.</p><h2 class="wp-block-heading">How to read a quote: expense items and price ranges</h2><p class="wp-block-paragraph">A well-prepared quote is not just a single final number, but a document that breaks down the project into clear line items. This allows you to understand where your money is going, compare different offers properly, and identify any hidden costs. Below you&#039;ll find the items that come up most often, with purely indicative price ranges: they serve to guide you, not to set a fixed rate, because every figure depends on how complex your project is.</p><ul class="wp-block-list"><li>Analysis and planning: the initial phase where processes and requirements are mapped out. Often represents 10-20% of the total (roughly €2,000–€10,000). Money well spent: it reduces surprises and rework.</li><li>Custom development: the largest line item. For smaller projects you&#039;ll start with several thousand euros, while more complex solutions can exceed tens of thousands. Always verify what&#039;s included and what&#039;s not.</li><li>Software licenses: costs for any third-party components or databases, sometimes one-time, sometimes annual. Ask whether license costs are your responsibility or the vendor&#039;s.</li><li>Cloud and infrastructure: the costs to host the application, generally monthly or annual, tied to storage, performance, and number of users. These should be treated as ongoing expenses, not one-time costs.</li><li>Training: hours spent teaching your team how to use the software properly. Often underestimated, it has a big impact on the actual return on your investment.</li><li>Support and maintenance: periodic fee for updates, fixes, and assistance. Roughly 15–25% annually of the development cost. Ask about response times and exactly what&#039;s covered.</li></ul><p class="wp-block-paragraph">When comparing multiple quotes, don&#039;t stop at the total: make sure they all include the same items and the same level of analysis. A lower quote that leaves out training or support is rarely actually the better deal.</p><blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow"><p>Always distinguish between one-time costs (analysis, development) and recurring costs (cloud, annual licenses, support): it&#039;s the latter that determine your spending over time.</p></blockquote><p class="wp-block-paragraph">In our case, development and cloud are handled together: this lets you read both the custom development work and the recurring infrastructure costs in a single quote, with greater clarity on what you&#039;ll pay now and down the line.</p><h2 class="wp-block-heading">Hidden costs and ROI: why the initial price isn&#039;t enough</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">The figure at the bottom of the quote tells only part of the story. An enterprise management system is not a purchase that ends upon delivery: it&#039;s a system that supports your company over the years and that, like any work tool, requires ongoing attention. Focusing solely on the initial development cost often leads to underestimating the real expense and, above all, to losing sight of what truly matters: how much that software will help you earn or save over time.</p><p class="wp-block-paragraph">Before you sign, ask your vendor for a clear breakdown of recurring charges. These, more than the starting price, determine the actual cost over a three to five year horizon.</p><ul class="wp-block-list"><li>Maintenance: fixing issues and making minor adjustments after release.</li><li>Updates: regulatory compliance, feature enhancements and compatibility with other systems.</li><li>Hosting: the costs of the infrastructure running the software, with fees varying based on storage, performance and required reliability.</li><li>Training: supporting the people who will use the management system every day, often crucial for actual adoption.</li></ul><p class="wp-block-paragraph">Once you&#039;ve identified these items, the logic needs to flip. The question is no longer &quot;how much does it cost?&quot;, but &quot;what will it return?&quot;. The return on investment of a custom-built management system is measured in very concrete terms: manual work hours eliminated, errors reduced, processes that once required multiple steps now happening automatically. If a task that took a team member several hours a week gets automated, that freed-up time has a precise economic value that repays your investment in a measurable way.</p><blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow"><p>An expensive software that saves 20 hours a month is a better investment than a cheap one that doesn&#039;t change the way you work.</p></blockquote><p class="wp-block-paragraph">For this very reason, development and cloud hosting should be considered together: building a custom solution and hosting it on reliable infrastructure means having a predictable recurring cost with no surprises, and the ability to grow the system alongside your company. Evaluate each quote not as an isolated expense, but as an investment for which you estimate the payback over time.</p><h2 class="wp-block-heading">How to prepare your quote request to get an accurate estimate</h2><p class="wp-block-paragraph">A quote is only as good as the information behind it. If you give suppliers vague descriptions (&quot;we&#039;d like a business management system for our company&quot;), you&#039;ll get equally vague numbers that are hard to compare. Spending a few days preparing your request is the most effective way to get realistic and comparable estimates.</p><p class="wp-block-paragraph">The starting point is mapping the processes that the software needs to support. This isn&#039;t about writing a technical specification—it&#039;s about describing how you work today: who does what, what steps are involved, where errors or time-wasters come from. This snapshot of real operations helps the supplier understand the actual complexity and size the offer correctly.</p><p class="wp-block-paragraph">Once you&#039;ve gathered the requirements, the critical next step is defining priorities. You rarely need to build everything at once: distinguishing what&#039;s essential in the first release from what can come later lets you control your initial investment and get started sooner.</p><ul class="wp-block-list"><li>Business objectives: what problem are you solving and how will you measure the outcome (time saved, errors reduced, orders handled).</li><li>Processes involved: list of activities to be digitized and departments affected.</li><li>Reference numbers: expected users, data and document volumes, work peaks.</li><li>Required integrations: accounting software, e-commerce, tools already in use.</li><li>Priorities: functions marked as &quot;essential&quot; versus &quot;nice-to-have&quot;.</li><li>Constraints: timelines, indicative budget, any regulatory requirements.</li></ul><p class="wp-block-paragraph">Providing these elements to all suppliers in the same format is what makes quotes truly comparable: you&#039;ll be evaluating offers based on the same scope, not apples and oranges.</p><blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow"><p>A well-conducted initial consultation is often worth more than the quote itself: it helps clarify priorities and avoid investing in features you don&#039;t need.</p></blockquote><p class="wp-block-paragraph">If you lack in-house technical expertise, bringing a development and cloud partner into an early analysis phase lets you turn operational needs into concrete requirements. This preliminary discussion makes clear what&#039;s truly worth building, which architecture makes sense, and how to evolve the solution over time, reducing the risk of surprises when the final quote arrives.</p><h2 class="wp-block-heading">Partnering with a technology provider: how RENOR &amp; Partners works</h2><p class="wp-block-paragraph">Choosing who will develop your business management software is a decision as important as setting your budget. A good technology partner doesn&#039;t just write code: they listen to your business needs, translate your processes into concrete solutions, and guide your project from the initial analysis through to production deployment and beyond. This is the approach we take at RENOR &amp; Partners.</p><p class="wp-block-paragraph">Before providing a cost estimate, we invest time in understanding how your business really operates. We analyze your workflows, identify priorities, and define together what&#039;s essential for the first release and what can be developed in later phases. This approach keeps initial costs down, avoids unnecessary features, and gives you a quote that matches reality—no surprises along the way.</p><p class="wp-block-paragraph">Our Development and cloud services handle the creation of custom software and its management in the cloud environment, ensuring accessibility, operational continuity, and scalability as you grow. We complement this with IT Consulting, which helps those who need support with strategic decisions too: which tools to integrate, how to structure your infrastructure, and how to evolve your system alongside your business.</p><p class="wp-block-paragraph">Working with a single point of contact for development, cloud, and consulting streamlines communication and saves time. Someone who understands the complete project can make faster, more consistent decisions and avoid those hidden costs that often arise from fragmentation across multiple vendors.</p><ul class="wp-block-list"><li>Process analysis and priority definition before the quote</li><li>Custom software development with cloud management</li><li>IT Consulting to support your technology choices over time</li><li>A single contact person for every project phase</li></ul><p class="wp-block-paragraph">If you&#039;re considering custom management software and want to understand what investment makes sense for your specific situation, the best way to start is to discuss your real objectives and processes. Contact us to request a personalized quote: we&#039;ll analyze your needs together and provide you with a clear, well-reasoned estimate.</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>Need concrete support?</strong> Discover our <a href="https://renor.it/en/services/development-and-cloud/">Development and cloud</a> service or <a href="https://renor.it/en/contact-us/">contact us</a> for a consultation.</p></div></div><p>L'articolo <a href="https://renor.it/en/blog/sviluppo-software-programmazione/customized-erp-software-quote-pricing-businesses/">Customized ERP Software Quote: Cost Guide for Businesses</a> proviene da <a href="https://renor.it/en/">RENOR &amp; Partners S.r.l.</a>.</p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Quote for developing a business web application: complete cost guide</title>
		<link>https://renor.it/en/blog/sviluppo-software-programmazione/business-web-application-development-quote/</link>
		
		<dc:creator><![CDATA[Simone Renzi]]></dc:creator>
		<pubDate>Tue, 07 Jul 2026 08:53:25 +0000</pubDate>
				<category><![CDATA[Software Development & Programming]]></category>
		<category><![CDATA[innovation]]></category>
		<category><![CDATA[lead generation]]></category>
		<category><![CDATA[renor]]></category>
		<category><![CDATA[technology]]></category>
		<guid isPermaLink="false">https://renor.it/blog/sviluppo-software-programmazione/business-web-application-development-quote/</guid>

					<description><![CDATA[<p>Learn how to calculate quotes for business web application development. Complete guide to costs and variables affecting pricing and project scope.</p>
<p>L'articolo <a href="https://renor.it/en/blog/sviluppo-software-programmazione/business-web-application-development-quote/">Quote for developing a business web application: complete cost guide</a> proviene da <a href="https://renor.it/en/">RENOR &amp; Partners S.r.l.</a>.</p>
]]></description>
										<content:encoded><![CDATA[<h2 class="wp-block-heading">What does it really cost to develop a business web application?</h2><p class="wp-block-paragraph">It&#039;s the first question anyone faces when undertaking a digital project, but the honest answer is: it depends. That&#039;s not a cop-out—it&#039;s the reality of custom work. A business web application isn&#039;t a shelf product with a fixed price tag: it&#039;s a tool built around your company&#039;s processes, goals, and constraints. That&#039;s why two seemingly similar quotes can differ significantly.</p><p class="wp-block-paragraph">In broad terms, the necessary budget is determined by some concrete variables that directly impact working hours and, consequently, the final cost. Knowing them upfront allows you to read a quote with a critical eye and compare vendors based on real factors, not just the bottom line.</p><ul class="wp-block-list"><li>The complexity of required features and the number of workflows to manage</li><li>The number of expected users and the access or permission levels needed</li><li>Integrations with systems already in use, such as ERP, CRM, or billing tools</li><li>Decisions regarding infrastructure, reliability, and solution scalability</li><li>Maintenance and support planned after release</li></ul><p class="wp-block-paragraph">In this article, we won&#039;t give you a magic number, because that would be misleading. Instead, we&#039;ll walk you through the items that make up a quote, so you understand where costs come from, which are negotiable, and where cutting corners doesn&#039;t pay. The goal is to put you in a position to discuss with any vendor from an informed standpoint, spotting solid proposals from those built solely to attract you with a low price.</p><p class="wp-block-paragraph">A good technology partner, after all, doesn&#039;t just write code. They handle both application development and the cloud infrastructure it runs on, evaluating with you the solutions best suited to your context. It&#039;s this big-picture view that makes the difference between an expense and an investment that creates value over time.</p><h2 class="wp-block-heading">The factors that determine quote pricing</h2><p class="wp-block-paragraph">A quote for web application development is never a fixed number: it&#039;s the result of precise choices regarding what the software should do, how many people will use it, and which systems it will need to integrate with. Understanding these variables helps you read a proposal critically and distinguish between what truly drives up costs and what&#039;s unnecessary.</p><ul class="wp-block-list"><li>Feature complexity: a platform with just a few screens and straightforward workflows costs less than an application packed with automations, calculations, different user roles, and sophisticated business logic. Each additional feature means design, development, and testing work.</li><li>Number of users and expected load: a management system used by ten people has different needs than a portal with thousands of simultaneous visitors. More users mean greater attention to performance and infrastructure.</li><li>Integrations with existing business software and ERP systems: connecting the application to systems already in place at the company (accounting, inventory, CRM) is often one of the most demanding parts, since it requires making different technologies communicate reliably.</li><li>Design and UX: a carefully crafted, intuitive interface that stays consistent reduces errors and training time, but requires dedicated work. It&#039;s an investment that pays for itself in everyday use.</li><li>Security: data protection, access management, and regulatory compliance aren&#039;t optional. The more sensitive the data being handled, the greater the effort required.</li><li>Cloud scalability: sizing the infrastructure so it can grow alongside the business prevents excessive costs upfront and avoids bottlenecks down the road.</li></ul><p class="wp-block-paragraph">The most effective way to keep the budget in check is to start with essential features and plan for gradual growth, rather than building everything at once. Our development and cloud service is built on this approach: we create the application and host it on infrastructure designed to adapt to your actual needs, so costs follow real usage growth instead of inflated assumptions.</p><blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow"><p>Every dollar in a quote tells a story: transparency means knowing which feature, which integration, or which security level justifies it.</p></blockquote><h2 class="wp-block-heading">How to Read and Compare a Software Quote (Without Getting Fooled)</h2><p class="wp-block-paragraph">Two quotes with the same bottom-line figure can hide very different realities. The difference doesn&#039;t lie in the number at the end of the page, but in the detail of each line item: what&#039;s included, what will be billed separately, and what&#039;s missing entirely. Learning to read a quote with a critical eye is the best way to avoid surprises halfway through a project or costs that resurface after launch.</p><p class="wp-block-paragraph">The first thing to verify is how person-hours are expressed. A serious quote breaks down activities by phase (analysis, development, testing, release) and assigns a realistic estimate to each one. Be wary of round, vague figures: if it&#039;s not clear how many hours are needed and for what, you don&#039;t have a tool to track where your money is going. Always ask what happens if a phase takes longer than expected and who bears that risk.</p><p class="wp-block-paragraph">The line items most often overlooked are those after launch. An application doesn&#039;t end the day it goes live: it needs to be maintained, updated, and supported. When comparing multiple offers, make sure these aspects are stated explicitly.</p><ul class="wp-block-list"><li>Maintenance: bug fixes, security updates, and technical adjustments. It should be clear whether it&#039;s included for a set period or billed as a subscription fee.</li><li>Hosting: where the application lives, what availability guarantees come with it, and who covers the monthly costs.</li><li>Post-launch support: response times, contact methods, and any hours already included in the price.</li><li>Code ownership: verify that the software developed remains your property, with no hidden restrictions.</li></ul><p class="wp-block-paragraph">A good technology partner isn&#039;t afraid of transparency: they put in writing what&#039;s included and what isn&#039;t, explain technical choices in language you can understand, and put you in a position to decide with full awareness. With our Development and cloud services, we work precisely in this direction: clear quotes, detailed line items, and continuity in managing both application and infrastructure, so you always know what you&#039;re paying for and why.</p><blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow"><p>A clear quote isn&#039;t the one that costs the least, but the one that lets you know in advance what you&#039;ll get and on what terms.</p></blockquote><h2 class="wp-block-heading">Custom development vs off-the-shelf solutions: which makes sense for your business</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&apos;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">Before you even look at a quote, many companies face a fundamental choice: adopt ready-made software (often subscription-based) or invest in a custom-built application. There&#039;s no one-size-fits-all answer. The right decision depends on whether your processes are standard or unique, your work volumes, and how central that software is to your business.</p><p class="wp-block-paragraph">Off-the-shelf solutions have real advantages: low upfront costs, fast deployment, and maintenance handled by the vendor. They&#039;re the smart choice when your needs match what the market already offers—like basic document management, email, or standard accounting.</p><p class="wp-block-paragraph">Custom development comes into play when packaged software forces you to reshape your processes around the tool, rather than the other way around. The typical warning signs are:</p><ul class="wp-block-list"><li>You use multiple disconnected systems that don&#039;t talk to each other, forcing duplicate data entry.</li><li>You pay licenses for dozens of users but only use a small fraction of the features.</li><li>Your processes give you a competitive edge and you don&#039;t want to flatten them into a standard template.</li><li>You expect growth or frequent changes that rigid software can&#039;t keep up with.</li></ul><p class="wp-block-paragraph">The right comparison isn&#039;t based on purchase price, but on return over time. A cheap subscription can become expensive as users, integrations, and forced customizations pile up. A custom-built application requires a bigger upfront investment, but eliminates manual work, cuts errors, and stays yours—adapting to your company instead of the other way around.</p><blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow"><p>The right question isn&#039;t &quot;how much does it cost today&quot;, but &quot;how much will it save or earn me over the next three years&quot;.</p></blockquote><p class="wp-block-paragraph">In practice, the best solution is often hybrid: targeted custom development where you need to stand out and gain efficiency, built on cloud infrastructure that ensures scalability and reliability. That&#039;s exactly where our development and cloud services come in: before we talk costs, it&#039;s worth analyzing your processes together to see where custom really pays off and where it doesn&#039;t.</p><h2 class="wp-block-heading">From request to release: how we manage a web project</h2><p class="wp-block-paragraph">A reliable quote comes from a clear working methodology. Knowing in advance what the phases of a project are helps you understand where resources go, when to make important decisions, and what results to expect at each stage. Here&#039;s how we typically structure the development of an enterprise web application.</p><h2 class="wp-block-heading">The main project phases</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>Requirements analysis and gathering: we start from your actual processes, not assumptions. We define objectives, stakeholders involved, and priorities, translating your business needs into concrete specifications.</li><li>Prototype: before writing the final code, we build a navigable version of the application. It lets you see and test the screens, adjust course early, and avoid rework costs later down the line.</li><li>Development: we build the application incrementally, with intermediate releases for you to review together. This keeps the project under control and minimizes surprises.</li><li>Cloud and deployment: we set up the environment where your application will run, ensuring reliability and accessibility for your users.</li><li>Release and support: we guide the launch into actual use and remain a reference point for fixes, improvements, and future enhancements.</li></ul><p class="wp-block-paragraph">This path is the heart of our Development and Cloud service: we design, build, and launch web applications tailored to your company&#039;s real needs. Working in phases isn&#039;t a formality—it&#039;s the most effective way to keep timelines, budget, and result quality aligned.</p><p class="wp-block-paragraph">Not always, though, is the starting point already clear. Many companies know they have a problem to solve, but don&#039;t yet know what the right solution is. In these cases, the analysis phase can be preceded by an IT Consulting engagement, useful for clarifying objectives and priorities before even discussing a quote. Getting the direction right at the beginning is the best way to secure a realistic estimate and a project that delivers real value.</p><blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow"><p>A transparent methodology, with verifiable phases and progressive releases, is the first guarantee of a quote that delivers on its promises.</p></blockquote><h2 class="wp-block-heading">Request a custom quote for your web application</h2><p class="wp-block-paragraph">At this point, you have the tools to understand what drives web application costs, how to evaluate an offer, and which approach best suits your business. The next step is turning this knowledge into a concrete project, tailored to your company&#039;s actual needs.</p><p class="wp-block-paragraph">Every serious quote starts with a simple question: what problem are you trying to solve? There&#039;s no standard price because no two companies are identical. That&#039;s why our first step isn&#039;t a price list, but a direct conversation where we analyze your goals, the processes you want to digitalize, and your budget priorities.</p><p class="wp-block-paragraph">During an initial strategic consultation, with no obligation, we work together to clarify what really matters:</p><ul class="wp-block-list"><li>The business objectives your application must support and the expected results</li><li>The essential features to release immediately and those that can wait for later phases</li><li>The technical scope of the project, with our development and cloud services covering implementation and deployment</li><li>A clear estimate of costs and timelines, broken down by phases and priorities</li></ul><p class="wp-block-paragraph">This approach ensures you receive a transparent quote where every line item corresponds to real value, not a generic figure. You know in advance what you&#039;re paying for, why, and what benefits you can expect to achieve.</p><blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow"><p>A good quote isn&#039;t the one with the lowest price, but the one that clearly describes what you&#039;ll receive and how it will contribute to your business goals.</p></blockquote><p class="wp-block-paragraph">If you have an idea to evaluate or a project ready to launch, contact RENOR for a dedicated consultation. We&#039;ll review your request and provide you with a personalized quote, built on your real needs rather than a pre-packaged solution. It&#039;s the simplest way to move from cost theory to a concrete and measurable proposal.</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>Need concrete support?</strong> Discover our <a href="https://renor.it/en/services/development-and-cloud/">Development and cloud</a> service or <a href="https://renor.it/en/contact-us/">contact us</a> for a consultation.</p></div></div><p>L'articolo <a href="https://renor.it/en/blog/sviluppo-software-programmazione/business-web-application-development-quote/">Quote for developing a business web application: complete cost guide</a> proviene da <a href="https://renor.it/en/">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/en/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[Software Development & Programming]]></category>
		<category><![CDATA[ai writing]]></category>
		<category><![CDATA[content marketing]]></category>
		<category><![CDATA[artificial intelligence]]></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/en/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/en/">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>



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



<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/en/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/en/">RENOR &amp; Partners S.r.l.</a>.</p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>From Zero to Packagist: Publishing a PHP Library on Composer</title>
		<link>https://renor.it/en/blog/sviluppo-software-programmazione/from-zero-to-packagist-publishing-a-php-library-on-composer/</link>
		
		<dc:creator><![CDATA[Simone Renzi]]></dc:creator>
		<pubDate>Mon, 12 May 2025 20:06:01 +0000</pubDate>
				<category><![CDATA[Software Development & Programming]]></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/from-zero-to-packagist-publishing-a-php-library-on-composer/</guid>

					<description><![CDATA[<p>Publishing a Composer package means making your code installable with a simple CLI command. composer require vendor/package and keeping updates, versions, and dependencies under control.To follow the guide, we need: Referring back to the article where we explored how to develop a descriptive statistics library, the repository structure was as follows: In the terminal, inside [&#8230;]</p>
<p>L'articolo <a href="https://renor.it/en/blog/sviluppo-software-programmazione/from-zero-to-packagist-publishing-a-php-library-on-composer/">From Zero to Packagist: Publishing a PHP Library on Composer</a> proviene da <a href="https://renor.it/en/">RENOR &amp; Partners S.r.l.</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p class="wp-block-paragraph">Publishing a Composer package means making your code installable with a simple CLI command.</p>

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

<p class="wp-block-paragraph">and keeping updates, versions, and dependencies under control.<br/>To follow the guide, we need:  </p>

<ul class="wp-block-list">
<li>Git version 2.0 or higher installed and configured</li>



<li>A GitHub account and a token with repo permission</li>



<li>Composer version 2.5 or higher installed <code>$PATH</code></li>



<li>A free account on Packagist.org (registered via GitHub using OAuth)</li>
</ul>

<p class="wp-block-paragraph">Referring back to the article where we explored how to develop a <a href="https://renor.it/en/blog/sviluppo-software-programmazione/a-descriptive-statistics-class-in-php/" data-type="link" data-id="https://renor.it/una-classe-di-statistica-descrittiva-in-php/">descriptive statistics library</a>, the repository structure was as follows:</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">In the terminal, inside the project folder, we type the command: </p>

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

<p class="wp-block-paragraph">Composer will ask us for some information, starting with the package name, which is expressed as vendor/package-name. In my case, since my account is named “thesimon82”, the package name will be <code>thesimon82/descriptive-statistics</code>. We confirm by pressing Enter.  </p>

<p class="wp-block-paragraph">Now we are asked for the description—<br/>for this project, we’ll enter: <code>Lightweight PHP class for descriptive statistics</code>.</p>

<p class="wp-block-paragraph">Next is the author field: if we’ve already configured it previously, Composer will show a default author; otherwise, we enter our name and surname manually. </p>

<p class="wp-block-paragraph">Minimum stability: if it’s a stable release, we enter “stable”.</p>

<p class="wp-block-paragraph">For Package Type, we enter: “library”.</p>

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

<p class="wp-block-paragraph">We are then asked whether we want to add, one by one, the production packages (require) that the library needs in order to work. In this case, the class is stand-alone (it only uses native PHP functions), so we don’t have any dependencies other than the minimum PHP version—therefore, we can safely answer “no”.<br/><br/><br/>If you’re thinking about PHPUnit for testing the class methods, remember that PHPUnit is only used during development and testing, so it should be placed in require-dev, not in require.<br/><br/><br/>This way, anyone installing the package in a production environment won’t have PHPUnit among their runtime dependencies.    </p>

<p class="wp-block-paragraph">The next prompt, in fact, asks whether we intend to define our development dependencies interactively (require-dev). Here, we type “yes”, and Composer will then prompt us to enter the name of the package.<br/><br/><br/>We now type:<br/><br/><br/><code>phpunit/phpunit</code><br/><br/><br/>Composer will return a list of matching packages—select phpunit/phpunit by entering the corresponding number.<br/><br/><br/>Then it will ask which version to include.<br/>We simply press Enter to install the latest available version.    </p>

<p class="wp-block-paragraph">It will now ask if we want to install any additional dependency packages, but since we don’t have any others, we simply press Enter. <br/>It will now ask if we want to add a PSR-4 autoload mapping for the classes, suggesting to map the namespace Thesimon82\DescriptiveStatistics.<br/>However, in our project we used Renor\\Statistics, so we type n to skip the proposal.</p>

<p class="wp-block-paragraph">Finally, we obtain a summary of the entered data:</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="{ "name": "thesimon82/descriptive-statistics", "description": "Lightweight PHP class for descriptive statistics", "type": "library", "require-dev": { "phpunit/phpunit": "^12.1" }, "license": "MIT", "authors": [ { "name": "Simone Renzi", "email": "info@simonerenzi.com" } ], "minimum-stability": "stable", "require": {}, "autoload": { "psr-4": { "Renor\\Statistics\\": "src/" } } } 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">    "name": "thesimon82/descriptive-statistics",</span></span>
<span class="line"><span style="color: #D4D4D4">    "description": "Lightweight PHP class for descriptive statistics",</span></span>
<span class="line"><span style="color: #D4D4D4">    "type": "library",</span></span>
<span class="line"><span style="color: #D4D4D4">    "require-dev": {</span></span>
<span class="line"><span style="color: #D4D4D4">        "phpunit/phpunit": "^12.1"</span></span>
<span class="line"><span style="color: #D4D4D4">    },</span></span>
<span class="line"><span style="color: #D4D4D4">    "license": "MIT",</span></span>
<span class="line"><span style="color: #D4D4D4">    "authors": [</span></span>
<span class="line"><span style="color: #D4D4D4">        {</span></span>
<span class="line"><span style="color: #D4D4D4">            "name": "Simone Renzi",</span></span>
<span class="line"><span style="color: #D4D4D4">            "email": "info@simonerenzi.com"</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">    "minimum-stability": "stable",</span></span>
<span class="line"><span style="color: #D4D4D4">    "require": {},</span></span>
<span class="line"><span style="color: #D4D4D4">    "autoload": {</span></span>
<span class="line"><span style="color: #D4D4D4">        "psr-4": {</span></span>
<span class="line"><span style="color: #D4D4D4">            "Renor\\Statistics\\": "src/"</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 class="line"><span style="color: #D4D4D4">Do you confirm generation [yes]? </span></span></code></pre></div>

<p class="wp-block-paragraph">Here we review the data, and if everything is correct, we confirm with “yes” and proceed to install the dependencies.</p>

<p class="wp-block-paragraph">At the end, we type the command:</p>

<p class="wp-block-paragraph"><code>composer dump-autoload</code> to regenerate the class autoloader.</p>

<p class="wp-block-paragraph">It’s time to make the commit using the following series of commands: </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 "feat: first stable release" 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 "feat: first stable release"</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">Now we move to GitHub, and we should see our repository with the latest commit—<br/>in my case: thesimon82 feat: first stable release.</p>

<p class="wp-block-paragraph">We copy the URL from the address bar at the top and head over to Packagist.</p>

<p class="wp-block-paragraph">Click on “Submit” at the top, then paste the GitHub link you copied into the text field. Press the Check button.<br/>At this point, Packagist will analyze the composer.json file and immediately display the package details.<br/>Clicking the “Submit” button at the bottom will create the package.    </p>

<p class="wp-block-paragraph">We’re done—now it’s time to test if everything works correctly.</p>

<p class="wp-block-paragraph">Create a new folder named “Stats Test”, then open the terminal and navigate into that folder using: <br/>Here we type:</p>

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

<p class="wp-block-paragraph">Now import this folder into your development environment and create a new file in the root directory named: 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;encoded_tag_open /&gt;?php require_once 'vendor/autoload.php'; use Renor\Statistics\DescriptiveStats; $stats = new DescriptiveStats([1, 2, 3, 4, 5,6.22]); echo $stats-&lt;encoded_tag_closed /&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">'vendor/autoload.php'</span><span style="color: #D4D4D4">;</span></span>
<span class="line"><span style="color: #569CD6">use</span><span style="color: #D4D4D4"> Renor\Statistics\</span><span style="color: #4EC9B0">DescriptiveStats</span><span style="color: #D4D4D4">;</span></span>
<span class="line"/>
<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">As we can see, we’re including the Composer-generated autoloader, which makes all classes mapped via PSR-4 available automatically—without the need for additional require statements. </p>

<p class="wp-block-paragraph">We define the namespace used in the DescriptiveStats class and instantiate a new object with a numeric dataset.<br/>You’ll recall that the class constructor automatically filters out non-numeric values, reindexes the array keys, and throws an exception if the resulting dataset is empty.<br/><br/><br/>Then, the method <code>mean()</code>is called, which computes the mean and displays it on the screen.   </p>

<p class="wp-block-paragraph">If you now run the command: <code>php test.php</code> from the terminal, and if everything was done correctly, you should see the result: <br/>3.5366666666667,<br/>which is precisely the approximate mean of the values we passed to the class constructor. </p>

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

<p class="wp-block-paragraph">We’ve seen how to transform a simple PHP class into a Composer package distributed on Packagist.<br/>Now the library can be installed with a single command, benefits from semantic versioning, continuous integration, and automation that updates the Packagist listing automatically with every new tag.  </p>

<p class="wp-block-paragraph">From this point on, the lifecycle is straightforward:<br/>you implement a feature, run the tests, increment the version, create the tag, and push it to GitHub.<br/>Packagist and Composer will take care of the rest! </p>

<p class="wp-block-paragraph">[starbox]</p>
<p>L'articolo <a href="https://renor.it/en/blog/sviluppo-software-programmazione/from-zero-to-packagist-publishing-a-php-library-on-composer/">From Zero to Packagist: Publishing a PHP Library on Composer</a> proviene da <a href="https://renor.it/en/">RENOR &amp; Partners S.r.l.</a>.</p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>A Descriptive Statistics Class in PHP</title>
		<link>https://renor.it/en/blog/sviluppo-software-programmazione/a-descriptive-statistics-class-in-php/</link>
		
		<dc:creator><![CDATA[Simone Renzi]]></dc:creator>
		<pubDate>Mon, 12 May 2025 19:06:41 +0000</pubDate>
				<category><![CDATA[Software Development & Programming]]></category>
		<category><![CDATA[applied mathematics]]></category>
		<category><![CDATA[arithmetic mean]]></category>
		<category><![CDATA[Composer]]></category>
		<category><![CDATA[data analysis]]></category>
		<category><![CDATA[descriptive statistics]]></category>
		<category><![CDATA[IQR]]></category>
		<category><![CDATA[mean absolute deviation]]></category>
		<category><![CDATA[median]]></category>
		<category><![CDATA[mode]]></category>
		<category><![CDATA[Packagist]]></category>
		<category><![CDATA[percentiles]]></category>
		<category><![CDATA[php]]></category>
		<category><![CDATA[PHP library]]></category>
		<category><![CDATA[PHP tutorial]]></category>
		<category><![CDATA[programming]]></category>
		<category><![CDATA[standard deviation]]></category>
		<category><![CDATA[standard error]]></category>
		<category><![CDATA[variance]]></category>
		<guid isPermaLink="false">https://renor.it/a-descriptive-statistics-class-in-php/</guid>

					<description><![CDATA[<p>In the world of software development, data analysis is becoming increasingly central. With the advent of artificial intelligence in the consumer market, many now use it to analyze statistical data as well. However, in many cases, the use of this technology is not required and is actually less efficient than a solid algorithm designed to [&#8230;]</p>
<p>L'articolo <a href="https://renor.it/en/blog/sviluppo-software-programmazione/a-descriptive-statistics-class-in-php/">A Descriptive Statistics Class in PHP</a> proviene da <a href="https://renor.it/en/">RENOR &amp; Partners S.r.l.</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p class="wp-block-paragraph">In the world of software development, data analysis is becoming increasingly central. With the advent of artificial intelligence in the consumer market, many now use it to analyze statistical data as well. However, in many cases, the use of this technology is not required and is actually less efficient than a solid algorithm designed to take input data and return output data in a “black-box” manner.  </p>

<p class="wp-block-paragraph">Artificial intelligence is now seen by many entrepreneurs as a trend, but it should only be used where it truly adds value. Speaking of efficiency, using AI to calculate a mean, a median, or a mode is not only like using a bazooka to kill a couple of flies, but it can also turn out to be slower, considering the inference times, compared to a finite state algorithm.  </p>

<p class="wp-block-paragraph">Even in contexts that are not strictly scientific or academic, knowing the fundamentals of descriptive statistics can prove extremely useful: from generating automated reports, to monitoring an application’s performance, and even to building dashboards or analytical tools. </p>

<p class="wp-block-paragraph">In this article, we will build a PHP class that calculates the main descriptive statistical indicators—such as mean, median, mode, variance, standard deviation, quartiles, and more—from scratch, without relying on external libraries. The code will be clean, reusable, and ready to be transformed into a Composer package, which will be the subject of a follow-up article. </p>

<h2 class="wp-block-heading">Designing a simple yet extensible class</h2>

<p class="wp-block-paragraph">To build a useful and easily integrable descriptive statistics class, we will adopt an object-oriented structure aligned with SOLID principles, avoiding external dependencies and ensuring the possibility of future extension (e.g., support for associative datasets or reading from CSV files). </p>

<p class="wp-block-paragraph">The class will be designed to operate on arrays of numerical values and efficiently compute the main statistical indicators. The goal is to provide a simple interface.  </p>

<p class="wp-block-paragraph">First, let’s create a new repository on GitHub, which you can find at the following 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">Let’s start implementing the methods.</p>

<p class="wp-block-paragraph">The project structure should be as follows: </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">As you can see, I have also included a folder for adding tests on the class methods (optional) using PHPUnit. The phpunit.xml file defines the test folder and the PHPUnit sources, which must be installed via Composer from the Packagist repository <code>phpunit/phpunit</code>, adding it as a development dependency using the command <code>composer require --dev phpunit/phpunit ^10</code>. </p>

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

<p class="wp-block-paragraph">The <strong>arithmetic mean</strong> (or average) of a set of <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;"/> numerical observations <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;"/> is obtained by summing all the values and dividing the result by the total number of observations. Formally, it is written as: </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/>where <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;"/> represents the arithmetic mean, <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;"/> is the sample size, and <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;"/> indicates the sum of all observations. This measure provides a concise indication of the central tendency of the data, although it is sensitive to the presence of outliers, which can cause it to deviate significantly from the actual “center” of the distribution. </p>

<p class="wp-block-paragraph">Let’s implement this method in our class. <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;encoded_tag_open /&gt;?php declare(strict_types=1); namespace Renor\Statistics; /** * 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-&lt;encoded_tag_closed /&gt;data = array_values($filtered); if (count($this-&lt;encoded_tag_closed /&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-&lt;encoded_tag_closed /&gt;data) / count($this-&lt;encoded_tag_closed /&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 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 class="line"><span style="color: #569CD6">namespace</span><span style="color: #D4D4D4"> </span><span style="color: #4EC9B0">Renor\Statistics</span><span style="color: #D4D4D4">;</span></span>
<span class="line"/>
<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 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">'is_numeric'</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 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">'The dataset must contain at least one numeric 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 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">As you can see, we have declared strict_types. This directive enforces PHP to avoid automatic type coercion, which is essential when we want full control over data types.   </p>

<p class="wp-block-paragraph">Since we will accept the data as an array of values, we declare a private property of the class <code>private array $data</code>.</p>

<p class="wp-block-paragraph">In the class constructor, we handle retrieving the data passed when instantiating the class to create a new object, verifying that the contents of the array <code>$data</code> are numeric, and we place the values inside the property <code>$this-&gt;data</code>.</p>

<p class="wp-block-paragraph">In the <code>mean()</code> method, we implement the mathematical formula for the mean: we sum all the elements of the passed array and divide by the number of elements, returning the result. </p>

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

<p class="wp-block-paragraph">The median represents the central value of an ordered set of observations and divides the sample into two halves of equal size. Given a series of <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;"/> values <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;"/> such that <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>If <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;"/> is odd, the median is simply the element in position <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-c6b5a201d1353c6363b2032beca6ef78_l3.png" class="ql-img-inline-formula quicklatex-auto-format" alt="&#92;&#116;&#101;&#120;&#116;&#123;&#77;&#101;&#100;&#105;&#97;&#110;&#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="116" style="vertical-align: -11px;"/></li>



<li>If <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;"/> is even, the median is the arithmetic mean of the two central elements: <br/><img loading="lazy" decoding="async" src="https://renor.it/wp-content/ql-cache/quicklatex.com-c276abe4acf0fe47b497d69c907e8566_l3.png" class="ql-img-inline-formula quicklatex-auto-format" alt="&#92;&#116;&#101;&#120;&#116;&#123;&#77;&#101;&#100;&#105;&#97;&#110;&#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="149" style="vertical-align: -6px;"/></li>
</ul>

<p class="wp-block-paragraph">Unlike the arithmetic mean, the median is robust to outliers, as it depends only on the ordering of the data and not on their magnitude. </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-&lt;encoded_tag_closed /&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 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 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 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 this method, I retrieve the data and sort it. We get the size and calculate the central index using integer division. For example, if we have 7 elements, <code>intdiv(7,2)</code> returns 3, which corresponds to the fourth position (remember that arrays in PHP are zero-based!). If the number of values is odd, there is a single perfectly central element, and it is returned. In the case of an even number of values, however, there is not just one central value but two: the ones in positions <code>$mid - 1</code> and <code>$mid</code>. By definition, the median is the arithmetic mean of these two values. We therefore sum the central elements and divide by 2.0 (using decimal notation to force floating-point division), which returns a float result. This way, the method returns the fiftieth percentile of the sample without modifying the original dataset and in accordance with the statistical definition for both odd and even-length series.        </p>

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

<p class="wp-block-paragraph">After the mean and the median, the third most commonly used indicator in descriptive statistics is the mode, that is, the value or values that occur most frequently within a set of observations. If we denote by <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;"/> the absolute frequency of a value <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;"/> in the sample, the mode is obtained as: </p>

<p class="wp-block-paragraph"><img loading="lazy" decoding="async" src="https://renor.it/wp-content/ql-cache/quicklatex.com-f1ac2cf45574d6c4e38aa17249827955_l3.png" class="ql-img-inline-formula quicklatex-auto-format" alt="&#92;&#116;&#101;&#120;&#116;&#123;&#77;&#111;&#100;&#101;&#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="178" style="vertical-align: -5px;"/>.</p>

<p class="wp-block-paragraph">We can distinguish, based on the input data series:</p>

<ul class="wp-block-list">
<li>Unimodal series when only one value has the highest frequency</li>



<li>Multimodal series when two or more values share the highest frequency</li>



<li>Series without a mode when all the values in the series appear only once each</li>
</ul>

<p class="wp-block-paragraph">The mode is particularly useful when the data are categorical or when one wants to highlight concentration around certain integer values. Unlike the mean and the median, it does not measure central tendency but rather the value or values that occur most frequently in the series. It is no coincidence that when a clothing item is “in fashion” it is because, compared to other items in a sales series, it turns out to be the most sold and therefore “the one most in fashion.”   </p>

<p class="wp-block-paragraph">Let’s therefore add the method to our class:</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 =&lt;encoded_tag_closed /&gt; occurrences $frequencies = array_count_values($this-&lt;encoded_tag_closed /&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 =&lt;encoded_tag_closed /&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 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 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 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 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> It scans the entire dataset and returns an associative array where the <strong>key</strong> is the observed value and the <strong>value</strong> is the number of times it occurs. This is a quick way to calculate <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;"/> for each <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/>With <code>max($frequencies)</code>, we obtain the highest number of occurrences present in the table; this corresponds to the value of <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;"/> in the mathematical definition.<br/>If the maximum frequency is 1, it means that each observation is unique. In this case, the method returns an empty array to indicate that no modal value exists.<br/>We iterate over the frequency table: for each key whose count equals the maximum frequency, we add that value (cast to float) to the array <code>$modes</code>. In this way, <strong>all</strong> modal values are included in the case of multimodality.<br/>Before returning the result, <code>sort($modes, SORT_NUMERIC)</code> ensures that the modes are sorted in ascending order, making the output more predictable.   </p>

<p class="wp-block-paragraph">In this way, we have covered all possible scenarios: unimodal, multimodal, and without a mode. </p>

<h2 class="wp-block-heading">Geometric mean</h2>

<p class="wp-block-paragraph">The <strong>geometric mean</strong> is the most appropriate measure of central tendency when the data represent <em>growth rates</em> or <em>ratios</em> (for example, percentage returns, variation indices, logarithmic scales).</p>

<p class="wp-block-paragraph">Given a series of <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;"/> <strong>strictly positive values</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;"/>, the geometric mean <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;"/> is defined as:</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">or, in a numerically more stable logarithmic form:</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/>This quantity corresponds to the “average” growth factor which, applied n times in sequence, yields the same result as the actual product of the values.</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-&lt;encoded_tag_closed /&gt;data as $value) { if ($value &lt;encoded_tag_open /&gt;= 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-&lt;encoded_tag_closed /&gt;data)); return exp($logSum / count($this-&lt;encoded_tag_closed /&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">'Geometric mean requires all values to be greater than zero.'</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 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">'log'</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/>Since the geometric mean is only defined for positive numbers, the method scans the dataset and throws a DomainException if it encounters values ≤ 0. This prevents mathematically incorrect (or complex) results.<br/>Instead of directly calculating the product (which could easily overflow), we convert each value using <code>log()</code>, sum the logarithms, and divide by <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;"/>. Based on the properties of logarithms:   <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/>By applying <code>exp()</code> to the average of the logarithms, we obtain the geometric mean.<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">Harmonic mean</h2>

<p class="wp-block-paragraph">The <strong>harmonic mean</strong> is the most appropriate measure of central tendency when the data represent <strong>speeds, ratios, or fractions</strong>—for example, kilometers per hour traveled at different paces, average cost per unit, or average return on investments calculated as “units per euro.”</p>

<p class="wp-block-paragraph">Given a series of <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;"/> positive values <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;"/> (no value can be zero, as it would appear in the denominator), the harmonic mean <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;"/> is defined as:<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 other words, it is calculated as the <strong>inverse of the arithmetic mean</strong> of the reciprocals. Compared to the arithmetic mean, the harmonic mean gives <strong>more weight to smaller values</strong>: it is therefore valuable when one wishes to strongly penalize poorer performances (e.g., the average time to travel one kilometer over multiple segments at different speeds). </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-&lt;encoded_tag_closed /&gt;data as $value) { if ($value &lt;encoded_tag_open /&gt;= 0) { throw new \DomainException('Harmonic mean requires all values to be greater than zero.'); } } $inverseSum = array_sum(array_map( static fn (float $v): float =&lt;encoded_tag_closed /&gt; 1.0 / $v, $this-&lt;encoded_tag_closed /&gt;data )); return count($this-&lt;encoded_tag_closed /&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">'Harmonic mean requires all values to be greater than zero.'</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 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 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">First, a domain check is performed: any value less than or equal to zero triggers a DomainException, otherwise the result would be undefined or become infinite. Then, a sum of the reciprocals is computed: <code>array_map()</code> calculates the reciprocal of each element, <code>array_sum()</code> sums them.<br/>The direct formula divides the number of observations <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;"/> by the obtained sum, according to the mathematical definition.  </p>

<h2 class="wp-block-heading">Truncated mean (or trimmed mean)</h2>

<p class="wp-block-paragraph">When a sample contains extreme <strong>outliers</strong> that risk distorting the arithmetic mean, an elegant solution is the <strong>truncated mean</strong> (or <em>trimmed mean</em>).</p>

<p class="wp-block-paragraph">A percentage <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;"/>% (typically 5% or 10%) is chosen, the sample is sorted, and the first <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;"/> smallest and the last <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;"/> largest observations are <strong>discarded</strong>, where:</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/>This way, a measure of central tendency is obtained that is <strong>more robust</strong> than the arithmetic mean but less drastic than the median.</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;encoded_tag_open /&gt; 0.0 || $percent &lt;encoded_tag_closed /&gt;= 50.0) { throw new \DomainException('Percent must be in the range 0 &lt;encoded_tag_open /&gt;= p &lt;encoded_tag_open /&gt; 50.'); } $count = count($this-&lt;encoded_tag_closed /&gt;data); if ($count &lt;encoded_tag_open /&gt; 3) { // Too few values to trim meaningfully; fall back to arithmetic mean return $this-&lt;encoded_tag_closed /&gt;mean(); } // Clone and sort to preserve original order $sorted = $this-&lt;encoded_tag_closed /&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 &lt;encoded_tag_closed /&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">'Percent must be in the range 0 &lt;= p &lt; 50.'</span><span style="color: #D4D4D4">);</span></span>
<span class="line"><span style="color: #D4D4D4">    }</span></span>
<span class="line"/>
<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 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 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 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">'Trim percentage removes all data.'</span><span style="color: #D4D4D4">);</span></span>
<span class="line"><span style="color: #D4D4D4">    }</span></span>
<span class="line"/>
<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 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">The method begins by verifying that the chosen trimming percentage makes sense: it must be greater than or equal to zero and strictly less than fifty, otherwise an exception is thrown; if, for example, we were to request the removal of 60% of the data from each tail, there would be nothing left to average.</p>

<p class="wp-block-paragraph">If the sample contains fewer than three observations, the function considers trimming meaningless and simply returns the arithmetic mean: with two values, removing even one would eliminate half the data, while with only one there is nothing to trim.</p>

<p class="wp-block-paragraph">The process then proceeds by <strong>cloning</strong> the original array and <strong>sorting</strong> it in ascending order; cloning preserves the order in which the data was provided to the object, while sorting is essential because trimming is applied starting from the extremes of the distribution.</p>

<p class="wp-block-paragraph">The number of elements to discard at each tail, denoted by <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;"/>, is obtained by multiplying the sample size by the requested percentage and rounding down; for example, if we have ten values and want a 10% trimmed mean, we will remove one element from the beginning and one from the end.</p>

<p class="wp-block-paragraph">Before proceeding, the method checks that “twice <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;"/>” is not equal to or greater than the length of the array: if it were, the trimming would remove all the data and the mean would no longer make sense; in such case, an additional exception is thrown.</p>

<p class="wp-block-paragraph">Once this check is passed, <code>array_slice()</code> extracts the central portion that remains after discarding the <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;"/> smallest and <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;"/> largest values; the arithmetic mean is then calculated on this subset, which is precisely the desired <strong>trimmed mean</strong>.</p>

<p class="wp-block-paragraph">The function thus returns a measure of central tendency that is more <strong>robust</strong> than the classic mean: the outliers, removed before the calculation, can no longer pull the result toward extreme values.</p>

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

<p class="wp-block-paragraph">The <strong>range</strong> is the simplest measure of dispersion: it indicates the total spread of the observed values, that is, the distance between the minimum and maximum extremes of the sample. If we denote </p>

<p class="wp-block-paragraph"><img loading="lazy" decoding="async" src="https://renor.it/wp-content/ql-cache/quicklatex.com-ecab5d2066b2307f31118966ea6fe121_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;&#97;&#110;&#100;&#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="424" style="vertical-align: -5px;"/>,</p>

<p class="wp-block-paragraph">then the 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;"/> is defined as</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">Although it is sensitive to outliers (the same value that affects the maximum or minimum also affects the range), this measure provides an immediate indication of the distribution’s <strong>spread</strong> and is often reported alongside the mean or median to give a quick overview of overall dispersion.</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-&lt;encoded_tag_closed /&gt;data) - min($this-&lt;encoded_tag_closed /&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">As can be seen, the method is very straightforward. It invokes the native PHP functions <code>max()</code> and <code>min()</code>, which each perform a single linear scan of the array to identify the largest and smallest values, respectively. Subtracting the minimum from the maximum yields the total spread of the sample; the result is returned as a float, consistent with the other methods in the class.   </p>

<h2 class="wp-block-heading">Quartiles and interquartile range (IQR)</h2>

<p class="wp-block-paragraph">To describe the dispersion of a sample more robustly than with the simple range, <strong>quartiles</strong> are used:</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;"/> – 25th percentile (first 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;"/> – 50th percentile (median)</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;"/> – 75th percentile (third quartile)</li>
</ul>

<p class="wp-block-paragraph">The interquartile range is defined as <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;"/> and represents the spread of the central half of the data. It is not very sensitive to outliers because it is based only on the values between the 25th and 75th percentiles of the distribution.  </p>

<p class="wp-block-paragraph">A classic use of the IQR is outlier detection using Tukey’s method (values less than <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;"/> or greater than <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: "Tukey hinges". * - 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-&lt;encoded_tag_closed /&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-&lt;encoded_tag_closed /&gt;medianOfArray($lower); $q3 = $this-&lt;encoded_tag_closed /&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-&lt;encoded_tag_closed /&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: "Tukey hinges".</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 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 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 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 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 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 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 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">'Cannot compute median of an empty array.'</span><span style="color: #D4D4D4">);</span></span>
<span class="line"><span style="color: #D4D4D4">    }</span></span>
<span class="line"/>
<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 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">When the <code>quartiles()</code> method is called, the first thing it does is create a copy of the internal data and sort it in ascending order; this copy preserves the original order provided by the user and allows working with a monotonically ordered vector, which is a necessary prerequisite for identifying quartiles. Immediately afterward, the variable <code>$n</code> stores the sample size, and <code>$mid</code> represents the central index calculated via integer division. With these two pieces of information, the median of the entire sample is determined, which becomes the second 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;"/>; if the number of observations is even, the median is the arithmetic mean of the two central values, whereas in the odd case, it coincides with the value at the central position.  </p>

<p class="wp-block-paragraph">Once <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;"/> is known, the sorted array is split into two halves. If the sample size is odd, the median must not be included in either the lower or upper part, so the function <code>array_slice</code> explicitly excludes it; if it is even, the division occurs exactly in half. At this point, the outer quartiles come into play: to calculate <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;"/> and <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;"/>, no new object is created—rather, the private helper <code>medianOfArray</code> is invoked on the two already sorted halves. This small routine receives a vector, counts its elements, determines the central index, and returns the median using the same logic as before; all of this remains confined within the class, keeping the public interface clean and avoiding any code duplication.   </p>

<p class="wp-block-paragraph">The <code>quartiles()</code> method finally returns an array with the three values <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 ascending order. Its counterpart, <code>iqr()</code>, simply unpacks that array, subtracts <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;"/> from <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;"/>, and returns the interquartile range, providing in a single call the most robust measure of dispersion in the class. </p>

<p class="wp-block-paragraph">In this setup, the logic for computing the median remains centralized within the private helper, and is reused both for quartiles and, implicitly, for any other internal functionality that might need to calculate a median on a sorted subset. Meanwhile, the public API continues to offer self-explanatory and easy-to-understand methods for anyone integrating your library.</p>

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

<p class="wp-block-paragraph">To measure how much the values deviate from their central tendency, <strong>variance</strong> is introduced, which calculates the mean of the squared deviations from the arithmetic mean. Given <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;"/> observations <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;"/>with mean <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;"/>, the <strong>population variance</strong> is defined as: </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">If instead the data represent a <strong>sample</strong> drawn from a larger population, the correct estimator (sample variance) divides by <img loading="lazy" decoding="async" src="https://renor.it/wp-content/ql-cache/quicklatex.com-88ba1a69ceedf1a3a91b958bb253b927_l3.png" class="ql-img-inline-formula quicklatex-auto-format" alt="&#110;&#32;&#8722;&#32;&#49;" title="Rendered by QuickLaTeX.com" height="12" width="19" 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">Variance returns a <strong>quadratic</strong> value: it is always non-negative and increases rapidly as deviations grow. For this reason, it is often used in conjunction with its square root (standard deviation) to return to the same units of measurement as the data.</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-&lt;encoded_tag_closed /&gt;data); // For a single value, population variance is 0, sample variance is undefined if ($n &lt;encoded_tag_open /&gt; 2 &amp;&amp; $sample) { throw new \DomainException('Sample variance requires at least two observations.'); } if ($n === 1) { return 0.0; } $mean = $this-&lt;encoded_tag_closed /&gt;mean(); $sumSquares = 0.0; foreach ($this-&lt;encoded_tag_closed /&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 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">'Sample variance requires at least two observations.'</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 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 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 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/>The method receives a flag indicating whether to calculate the population variance or the sample estimator. It begins by evaluating the dataset size: with only one value, the population variance is by definition zero, whereas the sample variance does not exist and an exception is thrown. Once the mean is known, the loop traverses each observation, subtracts the mean, squares the deviation, and accumulates it. After the summation is complete, the division is performed by <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;"/> or <img loading="lazy" decoding="async" src="https://renor.it/wp-content/ql-cache/quicklatex.com-88ba1a69ceedf1a3a91b958bb253b927_l3.png" class="ql-img-inline-formula quicklatex-auto-format" alt="&#110;&#32;&#8722;&#32;&#49;" title="Rendered by QuickLaTeX.com" height="12" width="19" style="vertical-align: 0px;"/> depending on the specified context, thus returning the desired measure of dispersion.   </p>

<h2 class="wp-block-heading">Standard deviation</h2>

<p class="wp-block-paragraph"><br/>The <strong>standard deviation</strong> is simply the square root of the variance: it serves to bring the measure of dispersion back to the same units as the original data. If variance indicates “how many squared units” the observations deviate on average from their mean, the standard deviation expresses that deviation in linear units, making it much more intuitive for a non-specialist reader. For the population, it is obtained as <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;"/> while in the sample case it is <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;"/>. Small standard deviation values indicate a distribution concentrated around the mean; large values indicate widely dispersed data.   </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-&lt;encoded_tag_closed /&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/>The method contains no additional logic: it simply calls <code>variance()</code> with the same flag and returns its square root, delegating all calculation and domain checks to the already tested algorithm.</p>

<h2 class="wp-block-heading">Standard error of the mean</h2>

<p class="wp-block-paragraph">When we observe only a sample from the population, the sample mean is an estimate subject to fluctuations: the smaller the sample, the more the estimate may vary from one sample to another. The <strong>standard error of the mean</strong> (<em>SEM</em>) precisely quantifies this expected variability. If s is the sample standard deviation and n is the sample size, the standard error is calculated as  </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">A small SEM indicates that the mean calculated from that sample is likely close to the true population mean; a large SEM suggests greater uncertainty. The SEM is also the basis for constructing confidence intervals for the mean. </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-&lt;encoded_tag_closed /&gt;data); if ($n &lt;encoded_tag_open /&gt; 2) { throw new \DomainException('Standard error requires at least two observations.'); } return $this-&lt;encoded_tag_closed /&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 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">'Standard error requires at least two observations.'</span><span style="color: #D4D4D4">);</span></span>
<span class="line"><span style="color: #D4D4D4">    }</span></span>
<span class="line"/>
<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/>The method first retrieves the sample size; if there is only one value, it makes no sense to speak of standard error, so a domain exception is raised. In all other cases, it calls the already implemented sample standard deviation method to obtain <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;"/>. By dividing <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;"/> by the square root of n, it computes the SEM according to the canonical statistical definition and returns the result as a floating-point value. In this way, all numerical logic remains consistent with the other measures of dispersion: the function relies on well-tested methods, does not replicate existing calculations, and guarantees a very simple usage contract.   </p>

<h2 class="wp-block-heading">Mean absolute deviation (MAD)</h2>

<p class="wp-block-paragraph">To measure dispersion in an intuitive way, without amplifying deviations by squaring them as variance does, the <strong>mean absolute deviation</strong> (MAD) is used. The idea is simple: calculate the absolute distance between each observation and the arithmetic mean, then take the average of those distances. If the sample consists of the values <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;"/> and their mean is <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;"/>, the mean absolute deviation is given by:  </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">The mean absolute deviation maintains the same units of measurement as the data, is less sensitive to outliers than the standard deviation, and offers an immediate interpretation: it indicates by how many units, on average, each value deviates from the center of the distribution.</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-&lt;encoded_tag_closed /&gt;mean(); $sumAbs = 0.0; foreach ($this-&lt;encoded_tag_closed /&gt;data as $v) { $sumAbs += abs($v - $mean); } return $sumAbs / count($this-&lt;encoded_tag_closed /&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 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 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/>The method first retrieves the arithmetic mean of the sample using the already existing <code>mean()</code> function. With this information, it iterates over each observation, subtracts the mean, takes the absolute value of the deviation, and accumulates it in <code>$sumAbs</code>. Once the loop is complete, it divides the sum of absolute deviations by the sample size, returning the result as a floating-point number. The logic remains linear and without conditional branches because the MAD formula does not require distinctions between population and sample: division by <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;"/> always applies.   </p>

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

<p class="wp-block-paragraph">To locate any given value along the distribution, <strong>percentiles</strong> are used: the <img loading="lazy" decoding="async" src="https://renor.it/wp-content/ql-cache/quicklatex.com-84cffb01cf803e6d1384d65c2b4f6805_l3.png" class="ql-img-inline-formula quicklatex-auto-format" alt="&#112;&#94;&#123;&#92;&#109;&#97;&#116;&#104;&#114;&#109;&#123;&#116;&#104;&#125;&#125;" title="Rendered by QuickLaTeX.com" height="19" width="23" style="vertical-align: -4px;"/> percentile identifies the point below which exactly <img loading="lazy" decoding="async" src="https://renor.it/wp-content/ql-cache/quicklatex.com-3cb16ffa488370248f87b01bc971188b_l3.png" class="ql-img-inline-formula quicklatex-auto-format" alt="&#112;&#92;&#44;&#92;&#37;" title="Rendered by QuickLaTeX.com" height="18" width="27" style="vertical-align: -4px;"/> of the ordered data fall. The 50th percentile coincides with the median, the 25th and 75th form the quartiles already implemented, and in general, knowing multiple percentiles allows for a very detailed description of the distribution’s shape. Since the sample is finite, the percentile position rarely corresponds to an exact integer index: interpolation between adjacent elements is therefore required. A widely adopted convention (Excel and NumPy “linear” method) consists in calculating:   </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">where <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;"/> is the sample size: if r falls between indices <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;"/> and <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;"/>, the percentile is the linear combination of the two values, weighted by the fractional part of <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;encoded_tag_open /&gt; 0.0 || $p &lt;encoded_tag_closed /&gt; 100.0) { throw new \DomainException('Percentile must be between 0 and 100.'); } $sorted = $this-&lt;encoded_tag_closed /&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">'Percentile must be between 0 and 100.'</span><span style="color: #D4D4D4">);</span></span>
<span class="line"><span style="color: #D4D4D4">    }</span></span>
<span class="line"/>
<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 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 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 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 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 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/>The method first validates that the requested percentile lies between 0 and 100 inclusive, thus ensuring consistency with the statistical definition. It then creates a sorted copy of the data, since any percentile localization requires a monotonically increasing vector. The boundary cases 0 and 100 are handled explicitly by returning the minimum and maximum of the sample, respectively. For all other values, the real rank <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;"/> is calculated, which may fall between two integer indices; the lower and upper indices define the interval containing the fractional position. If <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;"/> is already an integer, no interpolation is needed and the method returns the corresponding element directly. Otherwise, the lower and upper values are linearly combined using a weight equal to the decimal part of <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;"/>, yielding a continuous result that flows smoothly between the elements of the sample.     </p>

<h2 class="wp-block-heading">Minimum and Maximum</h2>

<p class="wp-block-paragraph"><br/>To complete the overview of descriptive measures, it is useful to be able to quickly retrieve the lower and upper extremes of the distribution. The <strong>minimum value</strong> indicates the smallest observation recorded in the sample; <strong>the maximum </strong>marks the largest. These two quantities, although extremely simple, are essential both for providing context to the data (knowing where the observed interval begins and ends) and as components of other statistics, such as the range you have already implemented. Since the dataset is entirely in memory, finding the minimum and maximum requires only a single linear scan, and the computational cost is negligible.   </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-&lt;encoded_tag_closed /&gt;data); } /** * Returns the maximum value of the dataset. * * @return float The largest observation. */ public function maxValue(): float { return (float) max($this-&lt;encoded_tag_closed /&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 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/>The PHP functions min() and max() scan the array only once; the cast ensures that the returned type is float, consistent with the rest of the API.</p>

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

<p class="wp-block-paragraph">With this final method, we have completed our <code>DescriptiveStats</code> class, which now encapsulates in a single component the most important tools of descriptive statistics: from measures of central tendency (arithmetic mean, median, mode, percentiles) to measures of dispersion (range, variance, standard deviation, IQR, MAD), including indicators of robustness (trimmed mean) and uncertainty (standard error).<br/>Each function is self-contained, strongly typed, and supported by automated PHPUnit tests, which we have not included here so as not to further lengthen an article already rich in content.  </p>

<p class="wp-block-paragraph">Thanks to this library, a PHP project can quickly analyze small datasets without external dependencies and without having to use artificial intelligence just to compute a “mode”, integrate statistical calculations into reports, dashboards, or APIs, and extend the class with additional indicators by leveraging a clear and consistent architecture. </p>

<p class="wp-block-paragraph">In the next article, we will see how to transform the code into a Composer package: we will create the final structure of the repository, review how to modify the <code>composer.json</code> file, configure CI to run the tests, and publish the library on Packagist, making it installable with a simple:</p>

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

<p class="wp-block-paragraph">In this way, you will be able to distribute your open-source solution, receive contributions from the community, and reuse it in any project with maximum simplicity.</p>

<p class="wp-block-paragraph">[starbox]</p>
<p>L'articolo <a href="https://renor.it/en/blog/sviluppo-software-programmazione/a-descriptive-statistics-class-in-php/">A Descriptive Statistics Class in PHP</a> proviene da <a href="https://renor.it/en/">RENOR &amp; Partners S.r.l.</a>.</p>
]]></content:encoded>
					
		
		
			</item>
	</channel>
</rss>
