Java 11, 1325 1379 1356 1336 1290 bytes
import java.math.*;String c(String s)throws Exception{String r="",T=r,a[],b[],z="\\.";int i=0,l,A[],M=0,m=s.length(),j,f=0,q=m;if(s.contains("(")){for(;i<m;){var c=s.charAt(i++);if(f<1){if(c==40){f=1;continue;}r+=c;}else{if(c==41&T.replaceAll("[^(]","").length()==T.replaceAll("[^)]","").length()){r+="x"+s.substring(i);break;}T+=c;}}return c(r.replace("x",c(T)));}else{for(a=s.split("[\\+\\-\\*/]"),A=new int[l=a.length];i<l;f=b.length>1&&(j=b[1].length())>f?j:f)M=(j=(b=a[i++].split(z))[0].length())>M?j:M;for(b=a.clone(),i=0;i<l;A[i]=b[i].contains(".")?j=b[i].length()-1:b[i].replaceAll("0*$","").length(),i++)for(q=(j=b[i].replace(".","").length())<q?j:q,j=a[i].split(z)[0].length();j++<M;)b[i]=0+b[i];double R=new Double(new javax.script.ScriptEngineManager().getEngineByName("JS").eval(s)+""),p;for(int x:A)m=x<m?x:m;m=m==M&R%1==0&(int)R/10%10<1&(j=(r=R+"").split(z)[0].length())>m?j-q>1?q:j:R>99?m:R%10==0?r.length()-1:m<1?1:m;R=new BigDecimal(R).round(new MathContext((R<0?-R:R)<1?m-1:m)).doubleValue();r=(m<M&(p=Math.pow(10,M-m))/10>R?(int)(R/p)*p:R)+"";l=r.length()-2;r=(r=f<1?r.replaceAll(z+"0$",""):r+"0".repeat(f)).substring(0,(j=r.length())<m?j:r.contains(".")?(j=r.replaceAll("^0\\.0+","").length())<m?m-~j:m+1:m);for(i=r.length();i++<l;)r+=0;return r.replaceAll(z+"$","");}}
+54 bytes para arreglar el caso de borde 501*2.0
(dio resultado 1002
antes, pero ahora correcto 1000
).
Ahora entiendo por qué este desafío no tuvo respuesta durante casi dos años ...>.> Este desafío tiene casos más especiales que el idioma holandés, que dice algo ...
Java ciertamente no es el idioma adecuado para este tipo de desafíos (o cualquier codegolf desafío para el caso ...; p), pero es el único lenguaje que conozco lo suficientemente bueno como para incluso intentar un desafío difícil como este.
Formato de entrada como String
sin espacios (si eso no está permitido, puede agregar s=s.replace(" ","")
(+19 bytes) en la parte superior del método).
Pruébalo en línea.
Explicación:
Perdón por la larga publicación.
if(s.contains("(")){
for(;i<m;){
var c=s.charAt(i++);
if(f<1){
if(c==40){
f=1;
continue;}
r+=c;}
else{
if(c==41&T.replaceAll("[^(]","").length()==T.replaceAll("[^)]","").length()){
r+="x"+s.substring(i);
break;}
T+=c;}}
return c(r.replace("x",c(T)));}
Esta parte se usa para entradas que contienen paréntesis. Obtendrá las partes separadas y usará llamadas recursivas.
0.4*(2*6)
se convierte 0.4*A
, donde A
es una llamada recursiva ac(2*6)
(8.3*0.02)+(1.*(9*4)+2.2)
se convierte A+B
, donde A
es una llamada recursiva c(8.3*0.02)
y B
una llamada recursiva a c(1.*(9*4)+2.2)
→ que a su vez se convierte 1.*C+2.2
, donde C
es una llamada recursiva ac(9*4)
for(a=s.split("[\\+\\-\\*/]"),A=new int[l=a.length];
i<l;
f=b.length>1&&(j=b[1].length())>f?j:f)
M=(j=(b=a[i++].split(z))[0].length())>M?j:M;
Este primer ciclo se usa para completar los valores M
y k
, donde M
es la mayor longitud entera con respecto a cifras significativas y k
la mayor longitud de decimales.
1200+3.0
se convierte en M=2, k=1
( 12, .0
)
999+2.00
se convierte en M=3, k=2
( 999, .00
)
300.+1-300.
se convierte en M=3, k=0
( 300, .
)
for(b=a.clone(),i=0;
i<l;
A[i]=b[i].contains(".")?j=b[i].length()-1:b[i].replaceAll("0*$","").length(),i++)
for(q=(j=b[i].replace(".","").length())<q?j:q,
j=a[i].split(z)[0].length();
j++<M;)
b[i]=0+b[i];
Este segundo bucle se usa para llenar las matrices A
y b
también el valor q
, donde A
es la cantidad de cifras significativas, b
mantener los enteros con ceros a la izquierda para coincidir M
, y q
es la longitud más baja sin tener en cuenta los puntos.
1200+3.0
se convierte A=[2, 5] (12, 00030)
, b=[1200, 0003.0]
y q=2
( 30
)
999+2.00
se convierte A=[3, 5] (999, 00200)
, b=[999, 002.00]
y q=3
(ambos 999
y 200
)
300.+1-300.
se convierte A=[3, 3, 3] (300, 001, 300)
, b=[300., 001, 300.]
y q=1
( 1
)
501*2.0
se convierte A=[3, 4] (501, 0020)
, b=[501, 002.0]
y q=2
( 20
)
double R=new Double(new javax.script.ScriptEngineManager().getEngineByName("JS").eval(s)+"")
Utiliza un motor de JavaScript para evaluar la entrada, que se guardará R
como doble.
1200+3.0
se convierte R=1203.0
999+2.00
se convierte R=1001.0
300.+1-300.
se convierte R=1.0
for(int x:A)
m=x<m?x:m;
Esto establece m
el valor más pequeño en la matriz A
.
A=[2, 5]
se convierte m=2
A=[3, 5]
se convierte m=3
A=[3, 3, 3]
se convierte m=3
m=m==M // If `m` equals `M`
&R%1==0 // and `R` has no decimal values (apart from 0)
&(int)R/10%10<1 // and floor(int(R)/10) modulo-10 is 0
&(j=(r=R+"").split(z)[0].length())>m?
// and the integer-length of R is larger than `m`:
j-q>1? // If this integer-length of `R` minus `q` is 2 or larger:
q // Set `m` to `q` instead
: // Else:
j // Set `m` to this integer-length of `R`
:R>99? // Else-if `R` is 100 or larger:
m // Leave `m` the same
:R%10==0? // Else-if `R` modulo-10 is exactly 0:
r.length()-1 // Set `m` to the total length of `R` (minus the dot)
:m<1? // Else-if `m` is 0:
1 // Set `m` to 1
: // Else:
m; // Leave `m` the same
Esto se modifica en m
función de múltiples factores.
999+2.00 = 1001.0
& se m=3,q=3
convierte en m=4
(porque m==M
(ambos 3
) → R%1==0
( 1001.0
no tiene valores decimales) → (int)R/10%10<1
(se (int)1001.0/10
convierte en 100
→ 100%10<1
) → "1001".length()>m
( 4>3
) → "1001".length()-q<=1
( 4-3<=1
) → entonces se m
convierte en la longitud de la parte entera "1001"
( 4
))
3.839*4 = 15.356
& m=1,q=1
permanece m=1
(porque m==M
(ambos 1
) → R%1!=0
( 15.356
tiene valores decimales) → R<=99
→ R%10!=0
( 15.356%10==5.356
) → m!=0
→ así que m
permanece igual ( 1
))
4*7*3 = 84.0
& m=1,q=1
permanece m=1
(porque m==M
(ambos 1
) → R%1==0
( 84.0
no tiene valores decimales) → (int)R/10%10>=1
(se (int)84/10
convierte en 8
→ 8%10>=1
) → R<=99
→ R%10!=0
( 84%10==4
) → m!=0
→ así que m
permanece igual ( 1
))
6.0+4.0 = 10.0
& se m=2,q=2
convierte en m=3
(porque m!=M
( m=2, M=1
) → R<=99
→ R%10==0
( 10%10==0
) → se m
convierte en la longitud del total R
(menos el punto) "10.0".length()-1
( 3
))
0-8.8 = -8.8
& se m=0,q=1
convierte m=1
(porque m!=M
( m=0, M=1
) → R<=99
→ R%10!=0
( -8.8%10==-8.8
) → m<1
→ se m
convierte en 1
)
501*2.0 = 1001.0
& se m=3,q=2
convierte en m=2
(porque m==M
(ambos 3
) → R%1==0
( 1001.0
no tiene valores decimales) → (int)R/10%10<1
(se (int)1001.0/10
convierte en 100
→ 100%10<1
) → "1001".length()>m
( 4>3
) → "1001".length()-q>1
( 4-2>1
) → se m
convierte en q
( 2
)
R=new BigDecimal(R).round(new MathContext((R<0?-R:R)<1?m-1:m)).doubleValue();
Ahora R
se redondea según m
.
1001.0
y se m=4
convierte1001.0
0.258
& se m=3
convierte en 0.26
(porque abs(R)<1
, m-1
( 2
) en lugar de m=3
se usa dentro MathContext
)
-8.8
y se m=1
convierte-9.0
1002.0
y se m=2
convierte1000.0
m<M&(p=Math.pow(10,M-m))/10>R?(int)(R/p)*p:R;
Esto modifica la parte entera de R
si es necesario.
300.+1-300. = 1.0
& m=3,M=3
permanece 1.0
(porque m>=M
→ entonces R
permanece igual ( 1.0
))
0.4*10 = 4.0
& m=1,M=2
permanece 4.0
(porque m<M
→ (10^(M-m))/10<=R
( (10^1)/10<=4.0
→ 10/10<=4.0
→ 1<=4.0
) → R
permanece igual ( 4.0
))
300+1-300 = 1.0
& se m=1,M=3
convierte en 0.0
(porque m<M
→ (10^(M-m))/10>R
( (10^2)/10>1.0
→ 100/10>1.0
→ 10>1.0
) → entonces se R
convierte en 0.0
debido a int(R/(10^(M-m)))*(10^(M-m))
( int(1.0/(10^2))*(10^2)
→ int(1.0/100)*100
→ 0*100
→ 0
)
r=(...)+""; // Set `R` to `r` as String (... is the part explained above)
l=r.length()-2; // Set `l` to the length of `R` minus 2
r=(r=k<1? // If `k` is 0 (no decimal values in any of the input-numbers)
r.replaceAll(z+"0$","")
// Remove the `.0` at the end
: // Else:
r+"0".repeat(f)
// Append `k` zeroes after the current `r`
).substring(0, // Then take the substring from index `0` to:
(j=r.length())<m? // If the total length of `r` is below `m`:
j // Leave `r` the same
:r.contains(".")? // Else-if `r` contains a dot
(j=r.replaceAll("^0\\.0+","").length())<m?
// And `R` is a decimal below 1,
// and its rightmost decimal length is smaller than `m`
m-~j // Take the substring from index 0 to `m+j+1`
// where `j` is this rightmost decimal length
: // Else:
m+1 // Take the substring from index 0 to `m+1`
: // Else:
m); // Take the substring from index 0 to `m`
Este conjuntos R
a r
como secuencia, y lo modifica basa en varios factores.
1203.0
& se m=4,k=2
convierte 1203.
(porque k>=1
→ entonces se r
convierte en 1001.000
; r.length()>=m
( 8>=4
) → r.contains(".")
→ r.length()>=m
( 8>=4
) → subcadena del índice 0
a m+1
( 5
))
6.9
& m=2,k=2
permanece 6.9
(porque k>=1
→ entonces se r
convierte en 6.900
; r.length()>=m
( 5>=2
) → r.contains(".")
→ r.length()>=m
( 5>=2
) → subcadena del índice 0
a m+1
( 3
))
1.0
& se m=3,k=0
convierte 1
(porque k<1
→ se r
convierte en 1
; r.length()<m
( 1<3
) → subcadena del índice 0
a r.length()
( 1
))
25.0
& se m=4,k=4
convierte 25.00
(porque k>=1
→ entonces se r
convierte en 25.00000
; r.length()>=m
( 8>=4
) → r.contains(".")
→ r.length()>+m
( 8>=4
) → subcadena del índice 0
a m+1
( 5
))
0
& se m=1,k=0
queda 0
(porque k<1
→ así se r
queda 0
; r.length()>=m
( 1>=1
) → !r.contains(".")
→ subcadena del índice 0
a m
( 1
))
for(i=r.length();i++<l;)
r+=0;
Esto hace que los ceros finales vuelvan a la parte entera si es necesario.
r="12"
y se R=1200.0
convierter="1200"
r="1"
y se R=10.0
convierter="10"
r="8"
y se R=80.0
convierter="80"
return r.replaceAll(z+"$","");
Y finalmente devolvemos el resultado, después de haber eliminado los puntos finales.
1203.
se convierte 1203
5.
se convierte 5
Definitivamente se puede jugar un par de cientos de bytes, pero me alegra que esté funcionando ahora. Ya tomó un tiempo entender cada uno de los casos y lo que se preguntaba en el desafío. Y luego se necesitaron muchas pruebas y errores, pruebas y pruebas para llegar al resultado anterior. Y mientras escribía esta explicación arriba pude eliminar otros ± 50 bytes de código no utilizado ...
999 + 2.00
,.