将10的幂写为紧凑的常数形式

huangapple go评论89阅读模式
英文:

Writing powers of 10 as constants compactly

问题

我正在阅读最近发布的《The Go Programming Language》,到目前为止,阅读过程非常愉快(考虑到Brian Kernighan是其中一位作者,我对它的卓越表现并不感到意外)。

我在第3章遇到了以下练习:

练习 3.13
尽可能简洁地写出 KB、MB、一直到 YB 的 const 声明。

注意:在这个上下文中,KB、MB 等表示 1000 的幂次)

在这之前的一节中,介绍了 iota 作为一个有用的常量生成机制;特别是,前一段展示了一种定义 1024 的幂次的常量的简洁方式:

const (
    _ = 1 << (10 * iota)
    KiB
    MiB
    GiB
    TiB
    PiB
    EiB
    ZiB
    YiB
)

作者进一步提到了关于 10 的幂次的内容:

iota 机制有其局限性。例如,不可能生成更熟悉的 1000 的幂次(KB、MB 等),因为没有指数运算符。

我对这个练习感到困惑,因为期望的解决方案似乎比简单地手动列出 1000 的幂次要复杂一些(特别是在介绍了 iota 之后)。我觉得有一种巧妙的方法可以结合 iota 和其他东西来完成这个任务。

我考虑过找到一种系统的方法,从每个 1024 的幂次中减去“多余”的部分,以得到 1000 的幂次,但是这没有帮助我。然后我查看了二进制表示,试图推断出 iota 可能有用的一般模式,但是仍然没有找到。

我真的无法想象如何在没有指数运算符的情况下,通过一个递增的值(iota)生成 1000 的幂次。

有什么想法吗?

英文:

I'm reading the recently released The Go Programming Language, and it's been a joy so far (with Brian Kernighan being one of the authors, I wouldn't expect anything other than excellence anyway).

I've come across the following exercise on chapter 3:

>Exercise 3.13
>Write const declarations for KB, MB, up through YB as compactly as you can.

(NOTE: in this context, KB, MB, etc, denote powers of 1000)

This is preceded by a section where iota is introduced as a useful constants generator mechanism; in particular, the previous paragraph shows a nice and compact way to define the powers of 1024 as constants:

const (
    _ = 1 &lt;&lt; (10 * iota)
    KiB
    MiB
    GiB
    TiB
    PiB
    EiB
    ZiB
    YiB
)

The authors further mention this regarding powers of 10:

>The iota mechanism has its limits. For example, it's not possible to generate the more familiar powers of 1000 (KB, MB, and so son) because there is no exponentiation operator.

I'm struggling with this exercise because it looks like the expected solution is something a little more elaborate than simply spelling out the powers of 1000 by hand (especially since it appears after iota is introduced). I feel like there is some clever way to do this that uses iota in a subtle way combined with something else.

I thought about finding a systematic way to subtract the "excess" amount out of each of the powers of 1024 to get the powers of 1000, but it led me to nowhere. Then I looked at the binary representations to try and infer a general pattern where iota could be useful, but again, I got nothing.

I really can't see how one would generate powers of 1000 out of a single incrementing value (iota) without an exponentiation operator.

Any ideas?

答案1

得分: 11

你自己引用了这段话:

> iota 机制有其局限性。例如,无法生成更熟悉的 1000 的幂次方(KB、MB 等),因为没有指数运算符。

尽管作者不知道任何方法,但他们不希望你仍然找到一种方法。作者希望你创建常量声明,以尽可能紧凑的方式。

使用浮点数字面量

这是一种紧凑的方法。它利用了带有指数部分的浮点数字面量。想想看:写 1e3 比写 1000 还要短(更不用说其他的了)。

它还将所有标识符压缩到一个常量声明中,因此我们将 = 符号减少到 1 个。

这是一行代码(不包括空格的 67 个字符):

const ( KB, MB, GB, TB, PB, EB, ZB, YB = 1e3, 1e6, 1e9, 1e12, 1e15, 1e18, 1e21, 1e24 )

请注意,由于我们使用了浮点数字面量,常量标识符(KBMB...)表示浮点常量,尽管字面量的小数部分为零。

使用整数字面量,使用 KB 作为乘数

如果我们想要无类型的整数常量,我们必须为 KB1000。为了获得下一个常量,我们会自动将前一个标识符乘以 1000。但请注意,我们也可以将下一个常量乘以 KB,因为它恰好是 1000 - 但比前者短两个字符 :).

因此,这是无类型整数常量声明(不包括空格的 77 个字符):

const (KB,MB,GB,TB,PB,EB,ZB,YB = 1000,KB*KB,MB*KB,GB*KB,TB*GB,PB*KB,EB*KB,ZB*KB)

(抱歉去掉了空格,但希望它能适应一行。)

使用整数字面量,使用额外的 x 常量作为乘数

如果你还引入一个长度为 1 的额外 x 常量,并多次使用它进行乘法运算,而不是使用 *KB,甚至可以从上一个解决方案中节省 3 个字符:

使用额外的 x 常量(不包括空格的 74 个字符):

const (x,KB,MB,GB,TB,PB,EB,ZB,YB = 1000,x,x*x,MB*x,GB*x,TB*GB,PB*x,EB*x,ZB*x)

使用 rune 字面量

如果我们将 1000 常量指定为一个 rune 常量,并使用其代码点为 1000rune,即 &#39;Ϩ&#39;,甚至可以再缩短一个字符:

使用 rune 字面量 &#39;Ϩ&#39; 常量(不包括空格的 73 个字符):

const (x,KB,MB,GB,TB,PB,EB,ZB,YB = &#39;Ϩ&#39;,x,x*x,MB*x,GB*x,TB*GB,PB*x,EB*x,ZB*x)

请注意,这些将是 rune 常量,但与所有其他数值常量一样,它们表示任意精度的值,不会溢出。

英文:

You quoted it yourself:

> The iota mechanism has its limits. For example, it's not possible to generate the more familiar powers of 1000 (KB, MB, and so son) because there is no exponentiation operator.

The authors don't want you to still find a way despite they're not knowing any. The authors want you to create constant declarations for KB, MB etc. as compact as you can.

With Floating-point literals

Here's a compact way. This utilizes Floating-point literals with exponent part. Think of it: writing 1e3 is even shorter than writing 1000 (not to mention the rest...).

Also it compresses all identifiers into one constant specification, so we reduce the = signs to 1.

Here it is, just one line (67 characters without spaces):

const ( KB, MB, GB, TB, PB, EB, ZB, YB = 1e3, 1e6, 1e9, 1e12, 1e15, 1e18, 1e21, 1e24 )

Note that since we used floating-point literals, the constant identifiers (KB, MB...) denote floating-point constants, even though the literals' fractional parts are zero.

With integer literal, using KB as the multiplier

If we want untyped integer constants, we have to write 1000 for the KB. And to get the next one, we would automatically turn to multiply the previous identifier with 1000. But note that we can also multiply the next one with KB because it's exactly 1000 - but shorter by two characters :).

And so here are the untyped integer constant declarations (77 characters without spaces):

const (KB,MB,GB,TB,PB,EB,ZB,YB = 1000,KB*KB,MB*KB,GB*KB,TB*GB,PB*KB,EB*KB,ZB*KB)

(Sorry for removing spaces, but wanted it to fit in one line.)

With integer literal, using an extra x const as the multiplier

You can even gain 3 characters from the last solution if you also introduce a 1-char length const x which you use multiple times to do the multiplication instead of the *KB:

With an extra x const (74 characters without spaces):

const (x,KB,MB,GB,TB,PB,EB,ZB,YB = 1000,x,x*x,MB*x,GB*x,TB*GB,PB*x,EB*x,ZB*x)

With rune literal

We can even shorten it one more character if we specify the 1000 constant as a rune constant, with a rune whose code point is 1000, which is &#39;Ϩ&#39; - which is 1 character less 将10的幂写为紧凑的常数形式

With a rune literal &#39;Ϩ&#39; const (73 characters without spaces):

const (x,KB,MB,GB,TB,PB,EB,ZB,YB = &#39;Ϩ&#39;,x,x*x,MB*x,GB*x,TB*GB,PB*x,EB*x,ZB*x)

Note that these will be rune constants, but just as all other numeric constants, they represent values of arbitrary precision and do not overflow.

答案2

得分: 3

我认为这是不可能的,因为你想要表示一个函数 10^(3i),其中 i 是一个正整数,作为某个函数 f(i) 的形式,其中 f 是你的基本 go 函数(+、-、/、*)的复合函数。

只有对于 2^(10i) 才是可能的,因为 go 引入了另一个基本函数整数指数运算。所以如果 1 << y 允许 y 是浮点数,你就可以修改你的代码使用 1 << (log2(10) * 3 * i)。这将起作用,因为这等价于求解 10^(3i) = 2^y。两边取 log2,得到 y = log2(10) * 3 * i

但可悲的是,位移操作只适用于整数。

英文:

I would say that this is impossible because what you want is to represent a function 10^(3i) where i is a positive integer as some function f(i), where f is a compositive function of your elementary go functions (+, -, /, *).

It was possible for 2^(10i) only because go introduced another elementary function integer exponentiation. So if 1 &lt;&lt; y would allow y being float, you would be able to modify your code to use 1 &lt;&lt; (log2(10) * 3 * i). This would worked because this is equivalent to solving 10^(3i) = 2^y. Taking log2 of both sides y = log2(10) * 3 * i.

But sadly enough bitwise shift is an integer operation.

huangapple
  • 本文由 发表于 2015年12月7日 07:47:01
  • 转载请务必保留本文链接:https://go.coder-hub.com/34124294.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定