¿Por qué usar otras bases numéricas al programar?


35

Mis compañeros de trabajo y yo hemos estado empeñados en descubrir por qué alguien haría todo lo posible por programar números en una base que no sea la base 10.

Sugerí que quizás podría optimizar ecuaciones más largas colocando las variables en la base correcta con la que está trabajando (por ejemplo, si solo tiene conjuntos de 5 de algo sin restos, podría usar la base 5), pero no estoy seguro si eso es verdad

¿Alguna idea?


66
¿Tiene un ejemplo específico que planteó esta pregunta? Las cosas que están en base-2 o base-16 obviamente tienen sus beneficios, ya que es más fácil de entender para una computadora.
KDiTraglia

44
¿Qué se supone que significa "programar números en base ..."? Hay numeros Período. Están representados internamente en alguna base, pero eso en su mayoría no importa y no cambia ninguna regla aritmética.

12
@JMD: trabaje con los moderadores para eliminar una de sus dos publicaciones cruzadas y coloque una aquí en P.SE. La publicación cruzada en todos los sitios está mal vista. Los mods pueden migrar las preguntas por ti.

10
@JMD: la publicación cruzada aún no es algo que deba hacer. Hay un proceso de migración para tales preguntas, si es necesario .
Oded

2
@JMD No cruce la publicación, una pregunta que sea adecuada para más de un sitio es extremadamente rara. Esta vez, por ejemplo, su pregunta estaba fuera de tema en Stack Overflow. Pero incluso si su pregunta era adecuada para ambos sitios, generalmente está mal visto comprar su pregunta en los sitios. Todos estamos siendo voluntarios en nuestro tiempo aquí, podría haber esperado al menos un tiempo para evaluar las respuestas que estaba obteniendo en Stack Overflow antes de la publicación cruzada.
Yannis

Respuestas:


59

La razón habitual para escribir números, en código, en otra base que no sea la base 10, es porque estás jugando un poco.

Para elegir un ejemplo en C (porque si C es bueno para cualquier cosa, es bueno para el bit-twiddling), digamos que un formato de bajo nivel codifica un número de 2 bits y un número de 6 bits en un byte xx yyyyyy:

main() {
    unsigned char codevalue = 0x94; // 10 010100
    printf("x=%d, y=%d\n", (codevalue & 0xc0) >> 6, (codevalue & 0x3f));
}

produce

x=2, y=20

En tal circunstancia, escribir las constantes en hexadecimal es menos confuso que escribirlas en decimal, porque un dígito hexadecimal corresponde perfectamente a cuatro bits (medio byte; un 'mordisco') y dos a un byte: el número 0x3ftiene todos los bits establecido en el mordisco bajo, y dos bits establecidos en el mordisco alto.

También podría escribir esa segunda línea en octal:

printf("x=%d, y=%d\n", (codevalue & 0300) >> 6, (codevalue & 077));

Aquí, cada dígito corresponde a un bloque de tres bits. A algunas personas les resulta más fácil pensar en eso, aunque creo que es bastante raro en estos días.


Otro ejemplo podría ser el uso del "número mágico" 0xDEADBEEF. Ver esta publicación stackoverflow.com/questions/5907614/0xdeadbeef-vs-null
Etsitpab Nioliv

45

La razón principal por la que uso bases diferentes es cuando me importan los bits.

Es mucho más fácil de leer

int mask=0xFF;
byte bottom_byte = value & mask;

que

int mask=255;
byte bottom_byte = value & mask;

O imagina algo más complejo

int mask=0xFF00FF00;
int top_bytes_by_word = value & mask;

comparado con

int mask=4278255360; //can you say magic number!? 
int top_bytes_by_word = value & mask;

Aquí está muy claro cuál es la intención con los ejemplos hexadecimales porque el hexadecimal es básicamente una forma más compacta de binario ... En contraste, la base 10 (lo que usamos) no se correlaciona tan bien con el binario.

0xFF = b11111111 = 255
0xFFFF = b1111111111111111 = 65536
0xF0F0 = b1111000011110000 = 61680

También hay otras bases que puede usar en algunos idiomas. Encontrará muy poco uso de bases que no sean binario, hexadecimal y decimal. Algunas personas extrañas aún usan octal, pero eso es lo más esotérico que verá en un programa sensato.


2
Octal no es raro en absoluto, 0 es octal :) (vi que en algún lugar de la red de Stack Exchange, no puedo encontrarlo ahora).
gerrit

2
@ Earlz: personas con muchos dedos. :-)
Bryan Oakley

3
26 x 2 + 10 = Todas las letras mayúsculas y minúsculas y todos los números. En realidad no es tan inusual. También he visto utilizar Base 36, que es solo la versión sin distinción entre mayúsculas y minúsculas.
Darrel Hoffman

3
@vasile: Hay 60 minutos en una hora y 60 segundos en un minuto porque las personas usaban sistemas de base 60, no al revés. ¡Espero que no creas que hay algo en la naturaleza que dice que debe haber 60 minutos en una hora!
Joren

1
sí, lo leyeron en las estrellas y usaron base 60 porque midieron el tiempo. con 360 días (= 6x60) al año, no es una locura medir el tiempo en base 60.
Ytg

8

Como probablemente sepa, las computadoras se basan en binarios: esta es la base 2.

Es fácil convertir entre base 2 y 4, 8 y 16 (y múltiplos similares de 2), y mantener esta traducción en el código fuente puede hacer que trabajar con números sea mucho más fácil de razonar.

Para lenguajes de bajo nivel como Assembly y C, esto puede traducirse directamente a las operaciones del procesador (desplazamiento de bits para división y multiplicación, por ejemplo), lo que significa que el uso de estas bases numéricas termina con un código mucho más rápido.

Además, no todas las operaciones son operaciones numéricas; hay mapas de bits en los que es necesario manipular los bits directamente; el uso de una base 2 o uno de sus múltiplos para hacerlo facilita mucho las operaciones.

Si desea obtener más información, le recomiendo leer Code by Charles Petzold .


3
Al compilador no le importa un comino. Si bien es más fácil convertir entre las bases que enumeras, una conversión simple (lenta) para la base 10 tampoco es difícil, y la mayoría de los lenguajes útiles para la construcción del compilador (no usas ensamblaje para eso) tienen eso conversión disponible en su biblioteca estándar, por lo que es efectivamente gratis para los compiladores.

1
El uso de hexadecimal en C no se traduce en programas más rápidos. Al compilador no le importa qué base usas.
Charles Salvia

55
No importa en qué base esté escrito el programa, el compilador lo traduce a binario en tiempo de compilación. Las instrucciones de montaje son idénticas.
Karl Bielefeldt

2
De hecho, las computadoras empresariales se basan en un bool tri-enery: verdadero, falso y "archivo no encontrado"
Martin Beckett


4

Fuera de los programas altamente especializados, es bastante raro usar bases que no sean 10, 16 o 2.

La base 16 (hexadecimal) es útil simplemente porque el rango completo de un byte (0-255) se puede representar en dos dígitos (0x00-0xFF), lo que puede hacer que trabajar con volcados hexadecimales sin procesar o datos binarios sea mucho más fácil. El hexadecimal también es útil cuando se usan máscaras de bits con operadores bit a bit, ya que la correspondencia de dos dígitos a un byte ayuda con la legibilidad.

Más raramente, la base 2 (binaria) también se puede usar con operaciones bit a bit, pero muchos lenguajes de programación no admiten literales base-2, y de todos modos el hexadecimal es mucho más conciso y legible.

Base-8 (octal) también se usa a veces debido a los permisos de archivos UNIX. Aparte de eso, es bastante raro usar bases distintas de 10 fuera de contextos matemáticos altamente especializados.


Octal se usa a menudo para especificar valores de caracteres y, a veces, para volcar datos binarios.
Caleb

3

La razón válida más común para usar otras bases tiene que ver con la facilidad de conversión a base 2: es trivial convertir un número base-8 o base-16 a binario sin usar una calculadora al memorizar una tabla corta de ocho o dieciséis números:

 0000 0     0001 1     0010 2     0011 3
 0100 4     0101 5     0110 6     0111 7

 1000 8     1001 9     1010 A     1011 B
 1100 C     1101 D     1110 E     1111 F

Esto abre múltiples posibilidades:

  • Cuando un número representa una composición de números binarios significativos, puede determinar los componentes individuales sin una computadora. Por ejemplo, si un número de 24 bits representa un color en RGB, es trivial decir que 0xFF00FFes magenta (Rojo + Azul); la tarea es mucho más difícil cuando se te presenta16711935
  • Cuando un número representa una máscara de bits, es más práctico escribirlo como un número hexadecimal compacto, en lugar de un número binario mucho más largo
  • Ciertas arquitecturas hicieron todo lo posible para que su código binario fuera fácil de leer cuando se imprimían como números octales. PDP-11 era uno de esos sistemas: el bit más significativo le permitiría distinguir las operaciones de 8 bits de las de 16 bits; los dos últimos grupos octales le permitirán informar a los dos registros involucrados en la operación, y así sucesivamente. Conocía a varias personas que podían leer el código binario PDP-11 de la pantalla sin un desensamblador, pero necesitaban que el código de la máquina se imprimiera en el sistema octal.

2

A la computadora (o más exactamente al compilador) realmente no le importa en absoluto qué base numérica usa en su código fuente. Los lenguajes de programación más utilizados admiten las bases 8 (octal), 10 (decimal) y 16 (hexadecimal) directamente. Algunos también tienen soporte directo para números de base 2 (binarios). Los idiomas especializados también pueden admitir otras bases numéricas. (Por "soporte directo", quiero decir que permiten la entrada de números en esa base sin recurrir a trucos matemáticos como desplazamiento de bits, multiplicación, división, etc. en el código fuente mismo. Por ejemplo, C admite directamente base-16 con su0xprefijo de número y el conjunto de dígitos hexadecimales regulares de 0123456789ABCDEF. Ahora, tales trucos pueden ser útiles para hacer que el número sea más fácil de entender en contexto, pero siempre que pueda expresar el mismo número sin ellos, hacerlo, o no, es solo una conveniencia).

Al final, sin embargo, eso es intrascendente. Digamos que tiene una declaración como esta a continuación:

int n = 10;

La intención es crear una variable entera e inicializarla con el número decimal 10. ¿Qué ve la computadora?

i  n  t     n     =     1  0  ;
69 6e 74 20 6e 20 3d 20 31 30 3b (ASCII, hex)

El compilador tokenizará esto, y se dará cuenta de que está declarando una variable de tipo intcon el nombre n, y le asignará un valor inicial. ¿Pero cuál es ese valor?

Para la computadora, e ignorando los problemas de ordenación y alineación de bytes, la entrada para el valor inicial de la variable es 0x31 0x30. ¿Significa esto que el valor inicial es 0x3130 (12592 en base 10)? Por supuesto no. El analizador de idiomas debe seguir leyendo el archivo en la codificación de caracteres utilizada, por lo que se lee 1 0seguido de un terminador de instrucción. Dado que en este lenguaje se supone la base 10, esto se lee (al revés) como "0 unidades, 1 decenas, final". Es decir, un valor de 10 decimales.

Si especificamos un valor en hexadecimal y nuestro lenguaje utiliza 0xpara especificar que el siguiente valor está en hexadecimal, obtenemos lo siguiente:

i  n  t     n     =     0  x  1  0  ;
69 6e 74 20 6e 20 3d 20 30 78 31 30 3b (ASCII, hex)

El compilador ve 0x(0x30 0x78) y reconoce eso como el prefijo de base 16, por lo que busca un número válido de base 16 que lo siga. Hasta el terminador de la declaración, se lee10 . Esto se traduce en 0 "unos", 1 "sixteens", lo que equivale a 16 en la base 10. O 00010000 en la base 2. O, de lo contrario, le gustaría representarlo.

En cualquier caso, e ignorando las optimizaciones por simplicidad, el compilador asigna suficiente almacenamiento para contener el valor de una intvariable de tipo, y coloca allí el valor que leyó del código fuente en algún tipo de variable de retención temporal. Luego (probablemente mucho más tarde) escribe los valores binarios resultantes en el archivo de código objeto.

Como puede ver, la forma en que escribe valores numéricos en el código fuente es completamente intrascendente. Se puede tener una muy leve efecto sobre el tiempo de compilación, pero me imagino que (de nuevo, ignorando optimizaciones tales como el almacenamiento en caché de disco por el sistema operativo) cosas como la turbulencia aleatoria alrededor de los platos giratorios del disco, tiempos de acceso al disco, colisiones de bus de datos , etc., tienen un efecto mucho mayor.

En pocas palabras: no te preocupes por eso. Escriba los números en una base que sea compatible con el lenguaje de programación que elija y que tenga sentido sobre cómo se usará o leerá el número. Pasó mucho más tiempo leyendo esta respuesta de lo que nunca se recuperará en los tiempos de compilación al ser inteligente sobre qué base de números usar en el código fuente. ;)


1

por qué alguien haría todo lo posible para programar números en una base que no sea la base 10.

Aquí hay algunas razones que aún no aparecían ...

x00: algunas API de sistemas operativos y dispositivos de hardware esperan que los argumentos estén en hexadecimal / binario. Cuando codifica tales API, es más fácil usar los números en el mismo formato que la API espera en lugar de convertirlo entre diferentes bases. Por ejemplo, para enviar un byte de fin de mensaje a un servidor o para enviar un mensaje para cerrar una conexión a un canal de comunicación.

x01: es posible que desee que su aplicación represente caracteres no disponibles en ciertos teclados, como el signo de copyright (\ u00a9).

x02 - Para que algunas constantes / literales persistan (visualmente) en diferentes configuraciones culturales, especialmente cuando el código fuente / archivos se mueven a través de desarrolladores con diferentes configuraciones locales.

x03 - Para que su código se vea confuso y complejo - ¡Lo bueno es que C # no admite constantes octales!


1

La cuestión clave es representar una sola palabra del tamaño de la computadora de manera razonable. El 6502 era un procesador de 8 bits. El 4004 era un procesador de 4 bits.

Cuando se trata de un número de 4 u 8 bits funciona muy bien. Un número de 4 bits es un solo carácter hexadecimal. Un número de 8 bits (un byte) son dos dígitos hexadecimales. Los sistemas que tienen una potencia de palabra de 2 tamaños son los estándares más comunes en la actualidad: 16 bits, 32 bits, 64 bits. Todos estos se dividen entre 4 muy bien para la representación como hexadecimal.

Octal (base 8) se usó en sistemas donde el tamaño de la palabra era 12, 24 o 36. El PDP8, IBM Mainframe e ICL 1900 de días de antigüedad los usaban. Estas palabras se representaron más fácilmente usando octetos en lugar de un rango limitado de hexadecimales (sí, también se dividen en 4).

Aparentemente también hubo un ahorro de costos al usar la numeración de base 8. Representando 12 bits en BCD, el primer dígito solo puede ser 0-4 pero el segundo, tercero y cuarto pueden ser 0-9. Si esto se hizo como hexadecimal, uno tiene 3 caracteres hexadecimales, pero cada uno tiene 16 valores posibles. Era más barato producir un tubo nixie que solo tuviera 0-7 que uno que tuviera 0-9 (con lógica adicional para BCD) o 0-F para hexadecimal.

Todavía hoy se ve octal con permisos de archivo Unix (755, 644) donde el propietario, el grupo y el mundo tienen 3 bits que representan los permisos.


En el mundo de las matemáticas, ocasionalmente se hacen cosas extrañas con diferentes bases. Por ejemplo, una secuencia débil de Goodstein del proyecto euler 396 ... o algo más simple con números palindrómicos . Existe la propiedad de un número en la base N de que un número que es un múltiplo de N - 1 tendrá sus dígitos sumando un múltiplo de N - 1 . Además, si N - 1 es un cuadrado perfecto, esta propiedad también existe para sqrt ( N - 1 ). Esto tiene algunas aplicaciones en ciertos problemas matemáticos.


1
Octal se debió a que el PDP tenía bytes de 9/18 bits, un número octal representa 3 bits, por lo que si su byte es divisible por 3 tiene mucho sentido
Martin Beckett

1
Octal también se usó en algunos sistemas de 16 bits (especialmente el PDP-11), porque 15 , el número de bits excepto el bit de signo, se divide muy bien en 3. Se utilizó ampliamente en todo el sistema operativo UNIX original (por ejemplo, "od" es la herramienta estándar para volcar archivos binarios, y su formato predeterminado es octal de 16 bits en lugar de hexadecimal de 8 bits), no solo para permisos. También puede ser relevante que el conjunto de instrucciones PDP-11 tenga dos campos de operando de 6 bits.
Aleatorio832

Octal también se usó porque podía mostrarse en la tecnología en ese momento. Nexi tubos, alguien? ¿O otras pantallas 0-9? Las pantallas de AF tardaron en aparecer.
Jeremy J Starcher

1

En la industria financiera, existe un esquema de identificación que es efectivamente base 36 . Utiliza los números 0-9 y las letras BZ para representar dígitos valorados 0-35. Se salta las vocales para evitar que se generen nombres desagradables.

Sin embargo, no es perfecto. Hubo un tiempo en que una compañía desafortunada tenía la identificación B000BZ.


1

Motivo n. ° 1: porque todos los números a nivel de circuito están representados en la base 2 (el interruptor eléctrico está encendido o apagado). Razón # 2: porque en un nivel más alto que los circuitos reales, los bits se agrupan en bytes, y los bytes se pueden representar fácilmente como dos dígitos hexadecimales, cuando tomaría 3 dígitos decimales (y alguna validación) para representar todos los valores posibles de byte.

Entonces, si está trabajando en estos niveles (o aproximándolos, en algún entorno administrado), es más fácil trabajar en binario o hexadecimal que en decimal. Las situaciones en las que haría esto son variadas, pero generalmente nunca son situaciones en las que solo necesita aritmética básica.


1

Un área donde los números de base 16 (hexadecimales) se usan con mucha frecuencia es la especificación del color, especialmente cuando se usa HTML / CSS para la web. Los colores que usamos en las pantallas digitales se especifican usando una combinación de 3 valores de intensidad para 3 colores "base" (RGB - rojo, verde, azul) que se mezclan para crear cualquiera de los 16 millones de colores visualizables (usando color de 24 bits) )

Por ejemplo, el verde de intensidad completa en hexadecimal sería 0x00ff00y 65280en decimal. Ahora imagine tratar de mezclar "manualmente" un color en su cabeza que tenga partes iguales de rojo y azul, digamos a media intensidad, para crear un bonito color púrpura :) En hexadecimal esto se escribiría simplemente como 0x800080mientras el valor decimal para esto sería 8388736. Se vuelve aún más fácil cuando se trabaja con tonos de gris: 50% de gris es 0x808080(hexadecimal) y 8421504(decimal), 75% es 0xC0C0C0y 12632256, y así sucesivamente.

El uso del hexadecimal es mucho más intuitivo y cualquiera que esté familiarizado con este uso del color podrá "adivinar" el color inmediatamente con solo mirar el valor hexadecimal. También es mucho menos propenso a errores si necesita usar el mismo color varias veces (que suele ser el caso).

Echa un vistazo a cualquier página web (y en particular al CSS) para ver una cantidad loca de uso hexadecimal: D

NOTA: En CSS, los valores hexadecimales se escriben usando un #prefijo, por ejemplo: #00ff00para verde, y también a veces se acorta a solo tres dígitos, como #0f0por ejemplo para verde.


0

Para algunos algoritmos, la base 2 tiene más sentido que cualquier otra cosa. Por ejemplo, ¿preferiría escribir una función para atravesar un árbol binario o un árbol de 10 arios?

Pero, con mayor frecuencia, se usa la base 2 porque así es como las computadoras representan casi universalmente sus números. Esto significa que:

  • Muchas operaciones son más eficientes en la base 2:
    • los poderes de multiplicación, división y módulo de 2 son mucho más rápidos que la división general
    • Las banderas y los valores pequeños se pueden almacenar, recuperar y manipular de manera más eficiente como dígitos binarios de un número mayor.
  • Las operaciones que leen, escriben y manipulan archivos de datos y flujos de datos de red deben tratar directamente con el hecho de que están representados como números binarios.

Además, siempre existe la rara aplicación que inherentemente requiere una base impar que puede no ser 2 o 10.


2
Por supuesto que usaría un árbol de 10 arios. ¿Qué es este 2personaje extraño que estás usando?
CodesInChaos

0

Es sinceramente preferencia, si por alguna razón tienes polidactilia y tienes 11 dedos o te gusta contar con los dedos de los pies, así que te gusta trabajar en la base 20, honestamente depende de ti. Pero tenga en cuenta que, en un tema de universalidad, la mayoría de nosotros que tenemos que lidiar con bits y bytes a diario se marcará realmente si obtenemos algo que está haciendo manipulación de bits en la base 19.

RAZONES PARA LA BASE x

Base 10: modelo de todas nuestras cosas porque tenemos 10 dígitos de conteo (los pies son raros y malolientes, por lo que no los usamos).

Base 2 - Las computadoras usan esto para bits (encendido / apagado) esto está relacionado con niveles de voltaje legibles que se propagan por puertas / transistores / condensadores.

Base 8: antiguo, cuando las computadoras no eran súper grandes (o cuando eran espaciales), esto era bueno para algo u otro (no me gusta ni un poco)

Base 16: buena para mostrar mordiscos superiores e inferiores de un byte para la manipulación de bits. Esto es súper útil en el mundo embebido / fpga / hardware.

BASES NORMALES EN COMPUTADORAS

Para ir con preferencia, podría decirle exactamente cómo "en" un color está en un valor RGB hexadecimal que se me da, esto en consecuencia se puede representar en un solo int en el hardware y luego con algunos cambios se me puede devolver fácil de usar, 1 color complejo = 1 punto de datos que es bueno para el procesamiento de imágenes grandes con memoria limitada. Compare eso con una representación de base 10, podría agregarlos todos y almacenarlos en un número, pero qué número es cuál, o tal vez R es el tiempo 10000, G es 100 y B es su propio espacio, son muchas operaciones matemáticas , por lo general, las multiplicaciones cuestan más ciclos que un turno, por lo que su siguiente pieza de datos ya está en la cola antes de que haya terminado con su última pieza procesada, vaya, eso ya no está.

A veces es mejor trabajar en base 2, 8 o 16. Con la mayoría de las máquinas, multiplicar por 2 es solo un poco de cambio, son súper rápidas, lo mismo con una división por 2.

Para exponer aún más sobre la idea de un poco de tonterías. Cuando trabajo en un entorno integrado, he necesitado muchas veces para acceder a una serie de luces, interruptores u otros elementos mapeados de registro.

En este caso, asignar un carácter completo, byte o int a cada interruptor sería ineficiente y tonto, un interruptor o luz tiene 2 posiciones - encendido y apagado - ¿por qué asignaría algo que tiene hasta 256 posiciones, o 2 ^ 16 posiciones, etc. Cada luz en una matriz puede ser de 1 bit que se ajuste a 8 o 16 o 32 o 64 o 128 (ancho de su tipo de datos) en una sola palabra / registro. La eficiencia del espacio es necesaria y bastante bienvenida.

Usar cualquier cosa que sea básica 2 ^ n en la programación para cosas como manejar datos RGB, muchos datos de señal (GPS, audio, ascii, etc.) es mucho más simple en hexadecimal, binario y octal, ya que así es como se representa en la máquina y uno puede discernir más fácilmente lo que se presenta y cómo manipularlo.

UTILIZANDO BASES EXTRAÑAS

No hay eficiencia a menos que lo codifique. Desea la base 11, debe configurar un tipo de datos y sobrecargar a los operadores para que manejen su representación ante el usuario. No veo ninguna razón por la cual un sistema que contenga 5 elementos, y que solo contenga múltiplos de 5 elementos, deba convertirse en la matemática de cinco elementos. Además, es mejor que reces para que quien decida escribir su código para la base 271 lo documente bien o podrías dedicar más tiempo a comprenderlo de lo que vale para crear la base 271 porque todos los elementos son múltiplos de 271.



0

Me sorprende que todas las otras respuestas no hayan mencionado dos usos muy comunes en la informática para bases alternativas:

  1. Codificación : la codificación Base64, por ejemplo, es extremadamente común. La codificación simplemente interpreta una serie de bytes como un gran número binario (base-2) y convierte ese número en un número Base64 representado por dígitos ASCII.
  2. Compresión : a menudo es deseable representar un número binario, decimal o hexadecimal en una base más grande para acortar la representación. Por ejemplo, todos los acortadores de bits como bit.ly están haciendo esto. O puede hacerlo para acortar un GUID para su uso en una URL.

    - 821F6321-881B-4492-8F84-942186DF059B (base-16 guid) 
    becomes
    - RRIDHW463YD8YXX7MIDI (base-36)
    - 3UFmaWDjj9lifYyuT0 (base-62)
    
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.