Algarismos romanos para número

Converte um texto em algarismos romanos (I, V, X, L, C, D, M) para seu valor inteiro — ex. "MCMXCIV" -> 1994. Percorre o texto somando o valor de cada símbolo, exceto quando é menor que o próximo (notação subtrativa: "IV", "IX", "XL"...), caso em que subtrai. Usa Switch sobre texto para traduzir cada símbolo.

Abrir no editor →

Algoritmo de exemplo, pronto para executar passo a passo no navegador. Sem instalar nada.

Fluxograma

Fluxograma do algoritmo Algarismos romanos para número

Pseudocódigo

Algoritmo main
  // Convierte un texto en números romanos (I, V, X, L, C, D, M, en mayúsculas) a su valor entero — ej. "MCMXCIV" -> 1994. Algoritmo clásico: recorre el texto de izquierda a derecha sumando el valor de cada símbolo, salvo que sea MENOR que el símbolo siguiente (caso de la notación sustractiva: "IV", "IX", "XL"...), en cuyo caso se resta en vez de sumar.

  Leer texto
  resultado <- 0
  i <- 1
  Mientras i<=LONGITUD(texto)
    ValorSimbolo(SUBCADENA(texto,i,i), actual)
    Si i<LONGITUD(texto)
      ValorSimbolo(SUBCADENA(texto,i+1,i+1), siguiente)
    SiNo
      siguiente <- 0
    FinSi
    Si actual<siguiente
      resultado <- resultado - actual
    SiNo
      resultado <- resultado + actual
    FinSi
    i <- i + 1
  FinMientras
  Escribir "El número es: ", resultado
FinAlgoritmo

Funcion ValorSimbolo(simbolo, valor)
  // Traduce un carácter romano (I, V, X, L, C, D, M) a su valor numérico. Cualquier otro carácter (entrada mal formada) devuelve 0 — sin validación estricta, a propósito, para mantener el ejemplo simple.

  Segun simbolo
    Caso I:
      valor <- 1
    Caso V:
      valor <- 5
    Caso X:
      valor <- 10
    Caso L:
      valor <- 50
    Caso C:
      valor <- 100
    Caso D:
      valor <- 500
    Caso M:
      valor <- 1000
    De Otro Modo:
      valor <- 0
  FinSegun
FinFuncion

O mesmo algoritmo em Java

package org.desarrollo;

import java.util.ArrayList;
import java.util.Scanner;

/**
 * Proyecto Java generado por freeDFDWeb a partir de un diagrama DFD.
 */
public class FreeDFDMain {
    /**
     * Convierte un texto en números romanos (I, V, X, L, C, D, M, en mayúsculas) a su valor entero — ej. "MCMXCIV" -> 1994. Algoritmo clásico: recorre el texto de izquierda a derecha sumando el valor de cada símbolo, salvo que sea MENOR que el símbolo siguiente (caso de la notación sustractiva: "IV", "IX", "XL"...), en cuyo caso se resta en vez de sumar.
     *
     * @param args no utilizado — freeDFDWeb no pasa argumentos de línea de comandos.
     */
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        String texto = null;
        double resultado = 0.0;
        double i = 0.0;
        double[] actual = {0.0}; // Arreglo de 1 elemento: simula paso por referencia (Java no permite mutar un double pasado a otro método) — se usa como "actual[0]" en el resto del método
        double[] siguiente = {0.0}; // Arreglo de 1 elemento: simula paso por referencia (Java no permite mutar un double pasado a otro método) — se usa como "siguiente[0]" en el resto del método

        texto = scanner.nextLine();
        resultado = 0;
        i = 1;
        while (((i <= (double)(texto).length()))) {
            ValorSimbolo((texto).substring((int)(i) - 1, (int)(i)), actual);
            if (((i < (double)(texto).length()))) {
                ValorSimbolo((texto).substring((int)((i + 1)) - 1, (int)((i + 1))), siguiente);
            } else {
                siguiente[0] = 0;
            }
            if (((actual[0] < siguiente[0]))) {
                resultado = (resultado - actual[0]);
            } else {
                resultado = (resultado + actual[0]);
            }
            i = (i + 1);
        }
        System.out.println("El número es: " + fmt(resultado));
    }

    /**
     * Traduce un carácter romano (I, V, X, L, C, D, M) a su valor numérico. Cualquier otro carácter (entrada mal formada) devuelve 0 — sin validación estricta, a propósito, para mantener el ejemplo simple.
     *
     * @param simbolo double
     * @param valor double[] — por referencia (el subprograma lo reasigna; el valor final es visible para quien llama)
     */
    static void ValorSimbolo(double simbolo, double[] valor) {
        double _switch1 = simbolo;
        if (_switch1 == 0.0) {
            valor[0] = 1;
        } else if (_switch1 == 0.0) {
            valor[0] = 5;
        } else if (_switch1 == 0.0) {
            valor[0] = 10;
        } else if (_switch1 == 0.0) {
            valor[0] = 50;
        } else if (_switch1 == 0.0) {
            valor[0] = 100;
        } else if (_switch1 == 0.0) {
            valor[0] = 500;
        } else if (_switch1 == 0.0) {
            valor[0] = 1000;
        } else {
            valor[0] = 0;
        }
    }

    static boolean readBoolean(Scanner scanner) {
        String t = scanner.nextLine().trim().toLowerCase();
        if (t.equals("verdadero") || t.equals("true") || t.equals("1")) return true;
        if (t.equals("falso") || t.equals("false") || t.equals("0")) return false;
        throw new RuntimeException("Se esperaba Verdadero o Falso, se recibio: " + t);
    }

    static double readDouble(Scanner scanner) {
        return Double.parseDouble(scanner.nextLine().trim());
    }

    static ArrayList<Double> readVector(Scanner scanner) {
        ArrayList<Double> result = new ArrayList<>();
        for (String token : scanner.nextLine().split(",")) {
            String t = token.trim();
            if (!t.isEmpty()) result.add(Double.parseDouble(t));
        }
        return result;
    }

    /** Formatea un double sin ".0" final cuando es entero — replica cómo freeDFDWeb (JS) imprime números, ej. factorial(5) debe mostrar "120", no "120.0". */
    static String fmt(double d) {
        if (!Double.isInfinite(d) && !Double.isNaN(d) && d == Math.floor(d) && Math.abs(d) < 1e15) {
            return String.valueOf((long) d);
        }
        return String.valueOf(d);
    }

    /** `String.valueOf(true)` da "true" — el pseudolenguaje escribe e imprime "Verdadero"/"Falso". */
    static String boolStr(boolean b) {
        return b ? "Verdadero" : "Falso";
    }

    /** `ToChar(n)` de Flowgorithm: código de carácter → carácter. `Character.toChars` cubre también los puntos fuera del BMP (emoji), que no caben en un `char`. */
    static String toChar(double code) {
        int c = (int) code;
        if (c < 0 || c > 0x10FFFF) {
            throw new RuntimeException("ToChar(" + c + "): codigo de caracter fuera de rango");
        }
        return new String(Character.toChars(c));
    }

    /** `ToFixed(r, i)` de Flowgorithm: TRUNCA a `i` decimales, no redondea. `Locale.ROOT` para que el separador sea el punto siempre, igual que el resto del generador. */
    static String toFixed(double value, double digits) {
        int d = (int) digits;
        double factor = Math.pow(10, d);
        double truncated = (double)(long)(value * factor) / factor;
        return String.format(java.util.Locale.ROOT, "%." + d + "f", truncated);
    }

    static double vecGet(ArrayList<Double> v, int index) {
        int i = index - 1;
        if (i < 0 || i >= v.size() || v.get(i) == null) {
            throw new RuntimeException("La posición " + index + " del vector no tiene un valor asignado todavía");
        }
        return v.get(i);
    }

    static void vecSet(ArrayList<Double> v, int index, double value) {
        int i = index - 1;
        while (v.size() <= i) v.add(null);
        v.set(i, value);
    }

    static double div(double a, double b) {
        if (b == 0) throw new ArithmeticException("División por cero");
        return a / b;
    }

    static double mod(double a, double b) {
        if (b == 0) throw new ArithmeticException("Módulo por cero");
        return a % b;
    }

    static void sleep(double seconds) {
        try { Thread.sleep((long) (seconds * 1000)); } catch (InterruptedException e) { Thread.currentThread().interrupt(); }
    }
}

O mesmo algoritmo em Python

#!/usr/bin/env python3
"""
Programa generado por freeDFDWeb — pseudocódigo exportado a Python.
Para correr: python3 main.py (ver README.md)
"""
import math
import random
import sys
import time
import datetime


class DfdRuntimeError(Exception):
    pass


def read_boolean():
    t = input().strip().lower()
    if t in ('verdadero', 'true', '1'):
        return True
    if t in ('falso', 'false', '0'):
        return False
    raise DfdRuntimeError('Se esperaba Verdadero o Falso, se recibio: ' + t)


def read_double():
    return float(input().strip())


def read_vector():
    return [float(t.strip()) for t in input().split(',') if t.strip() != '']


def fmt(d):
    """Formatea sin ".0" final cuando es entero — replica cómo freeDFDWeb (JS) imprime números."""
    if math.isinf(d):
        return 'Infinity' if d > 0 else '-Infinity'
    if math.isnan(d):
        return 'NaN'
    if d == math.floor(d) and abs(d) < 1e15:
        return str(int(d))
    return str(d)


def bool_str(b):
    """`str(True)` da "True" (mayúscula) — el pseudolenguaje escribe e imprime "Verdadero"/"Falso"."""
    return 'Verdadero' if b else 'Falso'


def sgn(x):
    """`Sgn(n)` de Flowgorithm. Devuelve x tal cual en el cero para conservar el signo del -0.0, igual que `Math.sign` de JS."""
    if math.isnan(x):
        return x
    if x > 0:
        return 1.0
    if x < 0:
        return -1.0
    return x


def to_fixed(value, digits):
    """`ToFixed(r, i)` de Flowgorithm: TRUNCA a i decimales, no redondea."""
    d = int(digits)
    factor = 10 ** d
    truncated = math.trunc(value * factor) / factor
    return f'{truncated:.{d}f}'


def vec_get(v, index):
    i = index - 1
    if i < 0 or i >= len(v) or v[i] is None:
        raise DfdRuntimeError(f'La posición {index} del vector no tiene un valor asignado todavía')
    return v[i]


def vec_set(v, index, value):
    i = index - 1
    while len(v) <= i:
        v.append(None)
    v[i] = value


def div(a, b):
    if b == 0:
        raise DfdRuntimeError('División por cero')
    return a / b


def mod(a, b):
    if b == 0:
        raise DfdRuntimeError('Módulo por cero')
    # `math.fmod`, NUNCA el `%` nativo de Python — el signo del resultado de
    # `%` en Python sigue al DIVISOR (-7 % 3 == 2), mientras que JS (y el
    # intérprete real) usan resto con signo del DIVIDENDO (-7 % 3 == -1),
    # que es exactamente lo que `math.fmod` reproduce.
    return math.fmod(a, b)


def redon(x):
    """Redondeo tipo `Math.round` de JS (.5 siempre hacia +Infinity) — NUNCA `round()` nativo de Python (redondeo bancario: round(2.5) == 2)."""
    return math.floor(x + 0.5)


def ValorSimbolo(simbolo, valor):
    """
    Traduce un carácter romano (I, V, X, L, C, D, M) a su valor numérico. Cualquier otro carácter (entrada mal formada) devuelve 0 — sin validación estricta, a propósito, para mantener el ejemplo simple.

    Args:
        simbolo: float
        valor: float — por referencia (el subprograma lo reasigna; el valor final es visible para quien llama)
    """
    _switch_1 = simbolo
    if _switch_1 == 0:
        valor[0] = 1
    elif _switch_1 == 0:
        valor[0] = 5
    elif _switch_1 == 0:
        valor[0] = 10
    elif _switch_1 == 0:
        valor[0] = 50
    elif _switch_1 == 0:
        valor[0] = 100
    elif _switch_1 == 0:
        valor[0] = 500
    elif _switch_1 == 0:
        valor[0] = 1000
    else:
        valor[0] = 0

def main():
    """Convierte un texto en números romanos (I, V, X, L, C, D, M, en mayúsculas) a su valor entero — ej. "MCMXCIV" -> 1994. Algoritmo clásico: recorre el texto de izquierda a derecha sumando el valor de cada símbolo, salvo que sea MENOR que el símbolo siguiente (caso de la notación sustractiva: "IV", "IX", "XL"...), en cuyo caso se resta en vez de sumar."""
    actual = [0.0]  # Lista de 1 elemento: simula paso por referencia (Python no permite mutar un float pasado a otra función) — se usa como "actual[0]" en el resto de la función
    siguiente = [0.0]  # Lista de 1 elemento: simula paso por referencia (Python no permite mutar un float pasado a otra función) — se usa como "siguiente[0]" en el resto de la función

    texto = input()
    resultado = 0
    i = 1
    while (i <= float(len(texto))):
        ValorSimbolo((texto)[int(i) - 1:int(i)], actual)
        if (i < float(len(texto))):
            ValorSimbolo((texto)[int((i + 1)) - 1:int((i + 1))], siguiente)
        else:
            siguiente[0] = 0
        if (actual[0] < siguiente[0]):
            resultado = (resultado - actual[0])
        else:
            resultado = (resultado + actual[0])
        i = (i + 1)
    print("El número es: " + fmt(resultado))


if __name__ == '__main__':
    main()

O mesmo algoritmo em C#

using System;
using System.Collections.Generic;
using System.Globalization;

/// <summary>Excepción propia para errores de ejecución del programa generado (división por cero, índice de vector sin asignar, etc.) — mismo criterio que el `RuntimeError` real de freeDFDWeb.</summary>
class DfdRuntimeException : Exception {
    public DfdRuntimeException(string message) : base(message) { }
}

/// <summary>
/// Proyecto C# generado por freeDFDWeb a partir de un diagrama DFD.
/// </summary>
class Program {
    /// <summary>
    /// Convierte un texto en números romanos (I, V, X, L, C, D, M, en mayúsculas) a su valor entero — ej. "MCMXCIV" -> 1994. Algoritmo clásico: recorre el texto de izquierda a derecha sumando el valor de cada símbolo, salvo que sea MENOR que el símbolo siguiente (caso de la notación sustractiva: "IV", "IX", "XL"...), en cuyo caso se resta en vez de sumar.
    /// </summary>
    /// <param name="args">no utilizado — freeDFDWeb no pasa argumentos de línea de comandos.</param>
    static void Main(string[] args) {
        CultureInfo.CurrentCulture = CultureInfo.InvariantCulture;
        string texto = null;
        double resultado = 0.0;
        double i = 0.0;
        double actual = 0.0;
        double siguiente = 0.0;

        texto = Console.ReadLine();
        resultado = 0;
        i = 1;
        while ((i <= (double)(texto).Length)) {
            ValorSimbolo((texto).Substring((int)(i) - 1, (int)(i) - (int)(i) + 1), ref actual);
            if ((i < (double)(texto).Length)) {
                ValorSimbolo((texto).Substring((int)((i + 1)) - 1, (int)((i + 1)) - (int)((i + 1)) + 1), ref siguiente);
            } else {
                siguiente = 0;
            }
            if ((actual < siguiente)) {
                resultado = (resultado - actual);
            } else {
                resultado = (resultado + actual);
            }
            i = (i + 1);
        }
        Console.WriteLine("El número es: " + Fmt(resultado));
    }

    /// <summary>
    /// Traduce un carácter romano (I, V, X, L, C, D, M) a su valor numérico. Cualquier otro carácter (entrada mal formada) devuelve 0 — sin validación estricta, a propósito, para mantener el ejemplo simple.
    /// </summary>
    /// <param name="simbolo">double</param>
    /// <param name="valor">double — por referencia (el subprograma lo reasigna; el valor final es visible para quien llama)</param>
    static void ValorSimbolo(double simbolo, ref double valor) {
        double _switch1 = simbolo;
        if (_switch1 == 0.0) {
            valor = 1;
        } else if (_switch1 == 0.0) {
            valor = 5;
        } else if (_switch1 == 0.0) {
            valor = 10;
        } else if (_switch1 == 0.0) {
            valor = 50;
        } else if (_switch1 == 0.0) {
            valor = 100;
        } else if (_switch1 == 0.0) {
            valor = 500;
        } else if (_switch1 == 0.0) {
            valor = 1000;
        } else {
            valor = 0;
        }
    }

    static readonly Random Rnd = new Random();

    static bool ReadBoolean() {
        string t = (Console.ReadLine() ?? "").Trim().ToLowerInvariant();
        if (t == "verdadero" || t == "true" || t == "1") return true;
        if (t == "falso" || t == "false" || t == "0") return false;
        throw new Exception("Se esperaba Verdadero o Falso, se recibio: " + t);
    }

    static double ReadDouble() {
        return double.Parse(Console.ReadLine().Trim(), CultureInfo.InvariantCulture);
    }

    static List<double?> ReadVector() {
        List<double?> result = new List<double?>();
        foreach (string token in Console.ReadLine().Split(',')) {
            string t = token.Trim();
            if (t.Length > 0) result.Add(double.Parse(t, CultureInfo.InvariantCulture));
        }
        return result;
    }

    /// <summary>Formatea un double sin ".0" final cuando es entero — replica cómo freeDFDWeb (JS) imprime números.</summary>
    static string Fmt(double d) {
        if (double.IsPositiveInfinity(d)) return "Infinity";
        if (double.IsNegativeInfinity(d)) return "-Infinity";
        if (double.IsNaN(d)) return "NaN";
        if (d == Math.Floor(d) && Math.Abs(d) < 1e15) {
            return ((long)d).ToString(CultureInfo.InvariantCulture);
        }
        return d.ToString(CultureInfo.InvariantCulture);
    }

    /// <summary>`true.ToString()` da "True" (mayúscula) — el pseudolenguaje escribe e imprime "Verdadero"/"Falso".</summary>
    static string BoolStr(bool b) {
        return b ? "Verdadero" : "Falso";
    }

    /// <summary>`Sgn(n)` de Flowgorithm. Helper y no `Math.Sign`: ese LANZA sobre NaN, mientras el intérprete devuelve NaN. Devuelve x en el cero para conservar el -0.0.</summary>
    static double Sgn(double x) {
        if (double.IsNaN(x)) return x;
        if (x > 0) return 1.0;
        if (x < 0) return -1.0;
        return x;
    }

    /// <summary>`ToFixed(r, i)` de Flowgorithm: TRUNCA a i decimales, no redondea. `InvariantCulture` para que el separador sea el punto, igual que `Fmt`.</summary>
    static string ToFixed(double value, double digits) {
        int d = (int) digits;
        double factor = Math.Pow(10, d);
        double truncated = Math.Truncate(value * factor) / factor;
        return truncated.ToString("F" + d, CultureInfo.InvariantCulture);
    }

    static double VecGet(List<double?> v, int index) {
        int i = index - 1;
        if (i < 0 || i >= v.Count || !v[i].HasValue) {
            throw new DfdRuntimeException("La posición " + index + " del vector no tiene un valor asignado todavía");
        }
        return v[i].Value;
    }

    static void VecSet(List<double?> v, int index, double value) {
        int i = index - 1;
        while (v.Count <= i) v.Add(null);
        v[i] = value;
    }

    static double Div(double a, double b) {
        if (b == 0) throw new DfdRuntimeException("División por cero");
        return a / b;
    }

    static double Mod(double a, double b) {
        if (b == 0) throw new DfdRuntimeException("Módulo por cero");
        // El operador `%` nativo de C# para `double` SÍ coincide con el
        // signo de JS (confirmado real: -7 % 3 == -1 en ambos) — a
        // diferencia de Python, no hace falta ningún wrapper de signo.
        return a % b;
    }

    /// <summary>Redondeo tipo `Math.round` de JS (.5 siempre hacia +Infinity) — NUNCA `Math.Round()` directo (bancario en .NET: Math.Round(2.5) == 2).</summary>
    static double Redon(double x) {
        return Math.Floor(x + 0.5);
    }
}

O mesmo algoritmo em C++

#include <iostream>
#include <string>
#include <vector>
#include <optional>
#include <cmath>
#include <sstream>
#include <iomanip>
#include <algorithm>
#include <cstdlib>
#include <ctime>
#include <chrono>
#include <thread>
#include <charconv>
#include <stdexcept>

/**
 * Programa C++ generado por freeDFDWeb a partir de un diagrama DFD.
 */

const double PI = 3.14159265358979323846;

class DfdRuntimeError : public std::runtime_error {
public:
    explicit DfdRuntimeError(const std::string& message) : std::runtime_error(message) {}
};

std::string readLine() {
    std::string line;
    if (!std::getline(std::cin, line)) return "";
    if (!line.empty() && line.back() == '\r') line.pop_back();
    return line;
}

/** `std::stod` (usado por `toNumberOrThrow`) NO tira con texto no numérico de forma consistente en todos los casos (ignora sufijos raros) pero SÍ tira `std::invalid_argument` con texto totalmente no numérico — verificado real. Envuelto para relanzar como `DfdRuntimeError`, mismo tipo de excepción que el resto del programa generado. */
double toNumberOrThrow(const std::string& value) {
    try {
        return std::stod(value);
    } catch (const std::exception&) {
        throw DfdRuntimeError("Se esperaba un número, se encontró \"" + value + "\"");
    }
}

bool readBoolean() {
    std::string t = readLine();
    for (auto& c : t) c = (char)std::tolower((unsigned char)c);
    if (t == "verdadero" || t == "true" || t == "1") return true;
    if (t == "falso" || t == "false" || t == "0") return false;
    throw std::runtime_error("Se esperaba Verdadero o Falso, se recibio: " + t);
}

double readDouble() {
    return toNumberOrThrow(readLine());
}

std::vector<std::optional<double>> readVector() {
    std::vector<std::optional<double>> result;
    std::stringstream ss(readLine());
    std::string token;
    while (std::getline(ss, token, ',')) {
        size_t start = token.find_first_not_of(" \t");
        size_t end = token.find_last_not_of(" \t");
        if (start == std::string::npos) continue;
        result.push_back(toNumberOrThrow(token.substr(start, end - start + 1)));
    }
    return result;
}

/** Formatea sin ".0" final cuando es entero, con representación de ida y vuelta exacta para decimales (`std::to_chars`, C++17) — replica cómo freeDFDWeb (JS) imprime números. Diverge de JS solo en notación científica de magnitudes extremas (ver comentario de cabecera del archivo), gap aceptado. */
std::string fmt(double d) {
    if (std::isinf(d)) return d > 0 ? "Infinity" : "-Infinity";
    if (std::isnan(d)) return "NaN";
    char buf[64];
    if (d == std::floor(d) && std::abs(d) < 1e15) {
        auto res = std::to_chars(buf, buf + sizeof(buf), (long long)d);
        return std::string(buf, res.ptr);
    }
    auto res = std::to_chars(buf, buf + sizeof(buf), d);
    return std::string(buf, res.ptr);
}

/** `std::cout << bool` imprime "1"/"0" — el pseudolenguaje escribe e imprime "Verdadero"/"Falso". */
std::string boolStr(bool b) {
    return b ? "Verdadero" : "Falso";
}

/** `Sgn(n)` de Flowgorithm. Devuelve x en el cero para conservar el signo del -0.0, igual que `Math.sign` de JS. */
double sgn(double x) {
    if (std::isnan(x)) return x;
    if (x > 0) return 1.0;
    if (x < 0) return -1.0;
    return x;
}

/** `ToChar(n)`: punto de código → carácter. C++ es el único destino sin conversión nativa, así que codifica UTF-8 a mano — `std::string` acá son bytes, no puntos de código. */
std::string toCharStr(double code) {
    long long c = (long long) code;
    if (c < 0 || c > 0x10FFFF) {
        throw DfdRuntimeError("ToChar(" + std::to_string(c) + "): codigo de caracter fuera de rango");
    }
    std::string out;
    if (c < 0x80) {
        out += (char)c;
    } else if (c < 0x800) {
        out += (char)(0xC0 | (c >> 6));
        out += (char)(0x80 | (c & 0x3F));
    } else if (c < 0x10000) {
        out += (char)(0xE0 | (c >> 12));
        out += (char)(0x80 | ((c >> 6) & 0x3F));
        out += (char)(0x80 | (c & 0x3F));
    } else {
        out += (char)(0xF0 | (c >> 18));
        out += (char)(0x80 | ((c >> 12) & 0x3F));
        out += (char)(0x80 | ((c >> 6) & 0x3F));
        out += (char)(0x80 | (c & 0x3F));
    }
    return out;
}

/** `ToCode(c)`: inversa de `toCharStr` — decodifica el PRIMER punto de código UTF-8, no el primer byte (si no, una "ñ" daría 195). */
double toCode(const std::string& s) {
    if (s.empty()) {
        throw DfdRuntimeError("ToCode espera un texto de un caracter");
    }
    unsigned char b0 = (unsigned char)s[0];
    if (b0 < 0x80) return (double)b0;
    int extra = (b0 >= 0xF0) ? 3 : (b0 >= 0xE0) ? 2 : 1;
    long long cp = b0 & (0x3F >> extra);
    for (int i = 1; i <= extra; i++) {
        if ((size_t)i >= s.size()) {
            throw DfdRuntimeError("ToCode: texto UTF-8 mal formado");
        }
        cp = (cp << 6) | ((unsigned char)s[i] & 0x3F);
    }
    return (double)cp;
}

/** `ToFixed(r, i)` de Flowgorithm: TRUNCA a i decimales, no redondea. */
std::string toFixed(double value, double digits) {
    int d = (int) digits;
    double factor = std::pow(10.0, d);
    double truncated = std::trunc(value * factor) / factor;
    std::ostringstream out;
    out << std::fixed << std::setprecision(d) << truncated;
    return out.str();
}

std::string toUpperStr(const std::string& s) {
    std::string result = s;
    std::transform(result.begin(), result.end(), result.begin(), [](unsigned char c) { return std::toupper(c); });
    return result;
}

std::string toLowerStr(const std::string& s) {
    std::string result = s;
    std::transform(result.begin(), result.end(), result.begin(), [](unsigned char c) { return std::tolower(c); });
    return result;
}

double vecGet(std::vector<std::optional<double>>& v, int index) {
    int i = index - 1;
    if (i < 0 || (size_t)i >= v.size() || !v[i].has_value()) {
        throw DfdRuntimeError("La posición " + std::to_string(index) + " del vector no tiene un valor asignado todavía");
    }
    return *v[i];
}

void vecSet(std::vector<std::optional<double>>& v, int index, double value) {
    int i = index - 1;
    if ((size_t)(i + 1) > v.size()) v.resize(i + 1);
    v[i] = value;
}

/**
 * `dividir` y no `div`, que sería el nombre obvio: `div` YA EXISTE en la
 * biblioteca estándar de C (`<cstdlib>`, devuelve un `div_t`) y está
 * declarada aunque no se incluya ese encabezado. Con dos literales
 * enteros, `div(7, 2)` resuelve a la versión de C —coincidencia exacta—
 * y el programa generado NO COMPILA:
 *
 *     error: cannot convert 'div_t' to 'double'
 *
 * O sea: CUALQUIER programa con una división fallaba al exportar a C++.
 * Encontrado el 30-oct-2026 compilando de verdad lo exportado
 * (`scripts/equivalencia/comparar.mjs`); ninguna prueba lo veía porque
 * ninguna compilaba C++.
 */
double dividir(double a, double b) {
    if (b == 0) throw DfdRuntimeError("División por cero");
    return a / b;
}

double mod(double a, double b) {
    if (b == 0) throw DfdRuntimeError("Módulo por cero");
    // `%` NO COMPILA sobre `double` en C++ — `std::fmod` es la única forma.
    // Su signo SÍ coincide con JS (confirmado real), a diferencia de
    // Python, que necesitaba un wrapper de signo además del de cero.
    return std::fmod(a, b);
}

/** Redondeo tipo `Math.round` de JS (.5 siempre hacia +Infinity) — NUNCA `std::round()` directo (redondea siempre alejándose de cero: round(-2.5) == -3, distinto de Math.round(-2.5) == -2). */
double redon(double x) {
    return std::floor(x + 0.5);
}

// ---------------------------------------------------------------------------
// Programa
// ---------------------------------------------------------------------------

/**
 * Traduce un carácter romano (I, V, X, L, C, D, M) a su valor numérico. Cualquier otro carácter (entrada mal formada) devuelve 0 — sin validación estricta, a propósito, para mantener el ejemplo simple.
 * @param simbolo double
 * @param valor double — por referencia (el subprograma lo reasigna; el valor final es visible para quien llama)
 */
void ValorSimbolo(double simbolo, double& valor) {
    double _switch1 = simbolo;
    if (_switch1 == 0.0) {
        valor = 1;
    } else if (_switch1 == 0.0) {
        valor = 5;
    } else if (_switch1 == 0.0) {
        valor = 10;
    } else if (_switch1 == 0.0) {
        valor = 50;
    } else if (_switch1 == 0.0) {
        valor = 100;
    } else if (_switch1 == 0.0) {
        valor = 500;
    } else if (_switch1 == 0.0) {
        valor = 1000;
    } else {
        valor = 0;
    }
}

/**
 * Convierte un texto en números romanos (I, V, X, L, C, D, M, en mayúsculas) a su valor entero — ej. "MCMXCIV" -> 1994. Algoritmo clásico: recorre el texto de izquierda a derecha sumando el valor de cada símbolo, salvo que sea MENOR que el símbolo siguiente (caso de la notación sustractiva: "IV", "IX", "XL"...), en cuyo caso se resta en vez de sumar.
 */
int main() {
    std::string texto = "";
    double resultado = 0.0;
    double i = 0.0;
    double actual = 0.0;
    double siguiente = 0.0;

    texto = readLine();
    resultado = 0;
    i = 1;
    while ((i <= (double)(texto).length())) {
        ValorSimbolo((texto).substr((size_t)(i) - 1, (size_t)(i) - (size_t)(i) + 1), actual);
        if ((i < (double)(texto).length())) {
            ValorSimbolo((texto).substr((size_t)((i + 1)) - 1, (size_t)((i + 1)) - (size_t)((i + 1)) + 1), siguiente);
        } else {
            siguiente = 0;
        }
        if ((actual < siguiente)) {
            resultado = (resultado - actual);
        } else {
            resultado = (resultado + actual);
        }
        i = (i + 1);
    }
    std::cout << std::string("El número es: ") + fmt(resultado) << "\n";
    return 0;
}

O mesmo algoritmo em TypeScript

import * as fs from 'fs';

/**
 * Generado por freeDFDWeb, sin descripción en el diagrama original.
 */

class DfdRuntimeError extends Error {}

const inputLines: string[] = fs.readFileSync(0, 'utf-8').split('\n');
let inputIndex = 0;

/** Toda la entrada se lee de una sola vez al arrancar (ver cabecera del archivo) — cada llamada consume la siguiente línea ya bufferizada. */
function readLine(): string {
    return (inputLines[inputIndex++] ?? '').replace(/\r$/, '');
}

function readBoolean(): boolean {
    const t = readLine().trim().toLowerCase();
    if (t === 'verdadero' || t === 'true' || t === '1') return true;
    if (t === 'falso' || t === 'false' || t === '0') return false;
    throw new Error('Se esperaba Verdadero o Falso, se recibio: ' + t);
}

function readDouble(): number {
    return toNumberOrThrow(readLine().trim());
}

function readVector(): (number | undefined)[] {
    return readLine()
        .split(',')
        .map((t) => t.trim())
        .filter((t) => t.length > 0)
        .map((t) => toNumberOrThrow(t));
}

/** `Number(x)` nativo no tira error con texto no numérico (da `NaN`) — a diferencia del intérprete real (`toNumber`), que sí tira. Único punto donde este generador necesita reproducir ese comportamiento a mano. */
function toNumberOrThrow(value: string | number): number {
    const n = Number(value);
    if (Number.isNaN(n)) {
        throw new DfdRuntimeError(`Se esperaba un número, se encontró "${value}"`);
    }
    return n;
}

/** `String(true)` da "true" — el pseudolenguaje escribe e imprime "Verdadero"/"Falso". */
function boolStr(b: boolean): string {
    return b ? 'Verdadero' : 'Falso';
}

/** `ToFixed(r, i)` de Flowgorithm: TRUNCA a i decimales, no redondea — por eso no basta el `.toFixed()` nativo, que redondea. */
function toFixed(value: number, digits: number): string {
    const d = Math.trunc(digits);
    const factor = Math.pow(10, d);
    return (Math.trunc(value * factor) / factor).toFixed(d);
}

function vecGet(v: (number | undefined)[], index: number): number {
    const i = Math.trunc(index) - 1;
    const value = v[i];
    if (i < 0 || value === undefined) {
        throw new DfdRuntimeError(`La posición ${index} del vector no tiene un valor asignado todavía`);
    }
    return value;
}

function vecSet(v: (number | undefined)[], index: number, value: number): void {
    v[Math.trunc(index) - 1] = value;
}

function div(a: number, b: number): number {
    if (b === 0) throw new DfdRuntimeError('División por cero');
    return a / b;
}

function mod(a: number, b: number): number {
    if (b === 0) throw new DfdRuntimeError('Módulo por cero');
    // El `%` nativo de JS/TS coincide exacto con el del intérprete real
    // (mismo motor) — a diferencia de Python, no hace falta ningún wrapper
    // de signo, solo el chequeo de división por cero.
    return a % b;
}


/**
 * Traduce un carácter romano (I, V, X, L, C, D, M) a su valor numérico. Cualquier otro carácter (entrada mal formada) devuelve 0 — sin validación estricta, a propósito, para mantener el ejemplo simple.
 * @param simbolo number
 * @param valor number[] — por referencia (el subprograma lo reasigna; el valor final es visible para quien llama)
 */
function ValorSimbolo(simbolo: number, valor: number[]): void {
    const _switch1: number = simbolo;
    if (_switch1 === 0) {
        valor[0] = 1;
    } else if (_switch1 === 0) {
        valor[0] = 5;
    } else if (_switch1 === 0) {
        valor[0] = 10;
    } else if (_switch1 === 0) {
        valor[0] = 50;
    } else if (_switch1 === 0) {
        valor[0] = 100;
    } else if (_switch1 === 0) {
        valor[0] = 500;
    } else if (_switch1 === 0) {
        valor[0] = 1000;
    } else {
        valor[0] = 0;
    }
}

/**
 * Convierte un texto en números romanos (I, V, X, L, C, D, M, en mayúsculas) a su valor entero — ej. "MCMXCIV" -> 1994. Algoritmo clásico: recorre el texto de izquierda a derecha sumando el valor de cada símbolo, salvo que sea MENOR que el símbolo siguiente (caso de la notación sustractiva: "IV", "IX", "XL"...), en cuyo caso se resta en vez de sumar.
 */
function main(): void {
    let texto: string = '';
    let resultado: number = 0;
    let i: number = 0;
    let actual: number[] = [0]; // Arreglo de 1 elemento: simula paso por referencia (JS/TS no tiene parámetros por referencia para primitivos) — se usa como "actual[0]" en el resto de la función
    let siguiente: number[] = [0]; // Arreglo de 1 elemento: simula paso por referencia (JS/TS no tiene parámetros por referencia para primitivos) — se usa como "siguiente[0]" en el resto de la función

    texto = readLine();
    resultado = 0;
    i = 1;
    while ((i <= (texto).length)) {
        ValorSimbolo((texto).slice((i) - 1, i), actual);
        if ((i < (texto).length)) {
            ValorSimbolo((texto).slice(((i + 1)) - 1, (i + 1)), siguiente);
        } else {
            siguiente[0] = 0;
        }
        if ((actual[0] < siguiente[0])) {
            resultado = (resultado - actual[0]);
        } else {
            resultado = (resultado + actual[0]);
        }
        i = (i + 1);
    }
    console.log("El número es: " + String(resultado));
}

main();

Gerado pelo freeDFDWeb a partir do fluxograma acima. É o mesmo arquivo que o botão Exportar do editor baixa.

Abre e salva nos formatos que você já usa

Importa e exporta PSeInt (.psc) e Flowgorithm (.fprg), e abre arquivos .dfd do DFD clássico. Tudo no navegador, sem instalar nada: funciona em Windows, Mac, Linux, Chromebook e celular.